summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/configs/apalis_t30_defconfig402
-rw-r--r--arch/arm/configs/colibri_pxa_defconfig340
-rw-r--r--arch/arm/configs/colibri_t20_android_defconfig390
-rw-r--r--arch/arm/configs/colibri_t20_defconfig345
-rw-r--r--arch/arm/configs/colibri_t30_android_defconfig440
-rw-r--r--arch/arm/configs/colibri_t30_defconfig344
-rw-r--r--arch/arm/include/asm/exception.h19
-rw-r--r--arch/arm/include/asm/system.h7
-rw-r--r--arch/arm/kernel/irq.c2
-rw-r--r--arch/arm/kernel/smp.c2
-rw-r--r--arch/arm/kernel/traps.c1
-rw-r--r--arch/arm/mach-pxa/Kconfig4
-rw-r--r--arch/arm/mach-pxa/colibri-evalboard.c2
-rw-r--r--arch/arm/mach-pxa/irq.c2
-rw-r--r--arch/arm/mach-tegra/Kconfig22
-rw-r--r--arch/arm/mach-tegra/Makefile19
-rw-r--r--arch/arm/mach-tegra/asm_macros.h2
-rw-r--r--arch/arm/mach-tegra/board-apalis_t30-memory.c2091
-rw-r--r--arch/arm/mach-tegra/board-apalis_t30-panel.c514
-rw-r--r--arch/arm/mach-tegra/board-apalis_t30-pinmux.c487
-rw-r--r--arch/arm/mach-tegra/board-apalis_t30-power.c509
-rw-r--r--arch/arm/mach-tegra/board-apalis_t30.c1432
-rw-r--r--arch/arm/mach-tegra/board-apalis_t30.h140
-rw-r--r--arch/arm/mach-tegra/board-aruba-sdhci.c2
-rw-r--r--arch/arm/mach-tegra/board-cardhu-sdhci.c2
-rw-r--r--arch/arm/mach-tegra/board-colibri_t20-memory.c464
-rw-r--r--arch/arm/mach-tegra/board-colibri_t20-panel.c473
-rw-r--r--arch/arm/mach-tegra/board-colibri_t20-pinmux.c386
-rw-r--r--arch/arm/mach-tegra/board-colibri_t20-power.c287
-rw-r--r--arch/arm/mach-tegra/board-colibri_t20.c1579
-rw-r--r--arch/arm/mach-tegra/board-colibri_t20.h88
-rw-r--r--arch/arm/mach-tegra/board-colibri_t30-memory.c276
-rw-r--r--arch/arm/mach-tegra/board-colibri_t30-panel.c529
-rw-r--r--arch/arm/mach-tegra/board-colibri_t30-pinmux.c658
-rw-r--r--arch/arm/mach-tegra/board-colibri_t30-power.c503
-rw-r--r--arch/arm/mach-tegra/board-colibri_t30.c1556
-rw-r--r--arch/arm/mach-tegra/board-colibri_t30.h115
-rw-r--r--arch/arm/mach-tegra/board-e1853.h2
-rw-r--r--arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c2
-rw-r--r--arch/arm/mach-tegra/clock.h9
-rw-r--r--arch/arm/mach-tegra/common.c47
-rw-r--r--arch/arm/mach-tegra/devices.c25
-rw-r--r--arch/arm/mach-tegra/devices.h1
-rw-r--r--arch/arm/mach-tegra/gic.h2
-rw-r--r--arch/arm/mach-tegra/gpio-names.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/ac97.h87
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h11
-rw-r--r--arch/arm/mach-tegra/include/mach/kfuse.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/thermal.h2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-gpio.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-i2c.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-panel.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-pinmux.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sdhci.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku1-b00.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku1.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku13-b00.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku13.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku23-b00.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku23-c01.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku23.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku3.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku5-b00.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku5-c01.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku8-b00.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku8-c01.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku9-b00.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sku9-c01.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852.c2
-rw-r--r--arch/arm/mach-tegra/p852/board-p852.h2
-rw-r--r--arch/arm/mach-tegra/pcie.c3
-rw-r--r--arch/arm/mach-tegra/pm-t3.c6
-rw-r--r--arch/arm/mach-tegra/pm.h2
-rw-r--r--arch/arm/mach-tegra/powergate.c1
-rw-r--r--arch/arm/mach-tegra/sleep-t2.S2
-rw-r--r--arch/arm/mach-tegra/sleep-t3.S2
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c10
-rw-r--r--arch/arm/mach-tegra/tegra2_emc.c12
-rw-r--r--arch/arm/mach-tegra/tegra2_mc.h2
-rw-r--r--arch/arm/mach-tegra/tegra2_usb_phy.c2
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c3
-rw-r--r--arch/arm/mach-tegra/tegra3_speedo.c2
-rw-r--r--arch/arm/mach-tegra/tegra_fiq_debugger.c2
-rw-r--r--arch/arm/mach-tegra/tegra_usb_phy.h2
-rw-r--r--arch/arm/mach-tegra/usb_phy.c19
-rw-r--r--arch/arm/mm/fault.c1
-rw-r--r--arch/arm/mm/pageattr.c2
-rw-r--r--arch/arm/tools/mach-types4
-rw-r--r--drivers/ata/ahci-tegra.c1
-rw-r--r--drivers/hwmon/lm95245.c134
-rw-r--r--drivers/input/keyboard/gpio_keys.c2
-rw-r--r--drivers/input/touchscreen/Kconfig7
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/fusion_F0710A.c524
-rw-r--r--drivers/input/touchscreen/fusion_F0710A.h87
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c22
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c25
-rw-r--r--drivers/media/video/Kconfig7
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/adv7180.c172
-rw-r--r--drivers/media/video/max9526.c1102
-rw-r--r--drivers/media/video/tegra_v4l2_camera.c1198
-rw-r--r--drivers/mfd/Kconfig1
-rw-r--r--drivers/mfd/stmpe.c24
-rw-r--r--drivers/mfd/tps6586x.c40
-rw-r--r--drivers/mmc/host/sdhci-tegra.c8
-rw-r--r--drivers/mmc/host/sdhci.c13
-rw-r--r--drivers/mtd/devices/tegra_nand.c41
-rw-r--r--drivers/mtd/nand/nand_ids.c1
-rw-r--r--drivers/net/can/mcp251x.c13
-rw-r--r--drivers/net/can/sja1000/sja1000_platform.c12
-rw-r--r--drivers/net/igb/Makefile3
-rw-r--r--drivers/net/igb/e1000_82575.c276
-rw-r--r--drivers/net/igb/e1000_82575.h3
-rw-r--r--drivers/net/igb/e1000_defines.h33
-rw-r--r--drivers/net/igb/e1000_hw.h24
-rw-r--r--drivers/net/igb/e1000_i210.c603
-rw-r--r--drivers/net/igb/e1000_i210.h76
-rw-r--r--drivers/net/igb/e1000_mac.c1
-rw-r--r--drivers/net/igb/e1000_nvm.c1
-rw-r--r--drivers/net/igb/e1000_phy.c147
-rw-r--r--drivers/net/igb/e1000_phy.h22
-rw-r--r--drivers/net/igb/e1000_regs.h14
-rw-r--r--drivers/net/igb/igb.h16
-rw-r--r--drivers/net/igb/igb_ethtool.c103
-rw-r--r--drivers/net/igb/igb_main.c163
-rw-r--r--drivers/net/usb/asix.c4283
-rw-r--r--drivers/net/usb/asix.h558
-rw-r--r--drivers/net/usb/axusbnet.c1374
-rw-r--r--drivers/net/usb/axusbnet.h208
-rw-r--r--drivers/regulator/tps6586x-regulator.c81
-rw-r--r--drivers/staging/iio/adc/Kconfig7
-rw-r--r--drivers/staging/iio/adc/Makefile2
-rw-r--r--drivers/staging/iio/adc/stmpe-adc.c334
-rw-r--r--drivers/staging/iio/industrialio-core.c10
-rw-r--r--drivers/tty/serial/8250.c21
-rw-r--r--drivers/tty/serial/tegra_hsuart.c2
-rw-r--r--drivers/usb/gadget/android.c4
-rw-r--r--drivers/usb/gadget/f_rndis.c21
-rw-r--r--drivers/usb/gadget/tegra_udc.c19
-rw-r--r--drivers/usb/gadget/u_ether.h23
-rw-r--r--drivers/usb/host/ehci-tegra.c115
-rw-r--r--drivers/usb/otg/Kconfig8
-rw-r--r--drivers/usb/otg/Makefile1
-rw-r--r--drivers/usb/otg/colibri-otg.c268
-rw-r--r--drivers/usb/serial/option.c10
-rw-r--r--drivers/video/logo/Kconfig4
-rw-r--r--drivers/video/logo/Makefile2
-rw-r--r--drivers/video/logo/logo.c4
-rw-r--r--drivers/video/tegra/dc/dc.c6
-rw-r--r--drivers/video/tegra/dc/dc_priv.h6
-rw-r--r--drivers/video/tegra/dc/ext/dev.c32
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h2
-rw-r--r--drivers/video/tegra/dc/hdmi.c13
-rw-r--r--drivers/video/tegra/dc/mode.c285
-rw-r--r--drivers/video/tegra/dc/nvhdcp.c2
-rw-r--r--drivers/video/tegra/dc/window.c15
-rw-r--r--drivers/video/tegra/fb.c343
-rw-r--r--drivers/video/tegra/host/bus_client.c3
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c2
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c3
-rw-r--r--drivers/video/tegra/nvmap/nvmap.c6
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c3
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c3
-rw-r--r--drivers/watchdog/Kconfig15
-rw-r--r--drivers/watchdog/tegra_wdt.c200
-rw-r--r--include/asm-generic/gpio.h10
-rw-r--r--include/linux/colibri_usb.h28
-rw-r--r--include/linux/input/fusion_F0710A.h20
-rw-r--r--include/linux/linux_logo.h1
-rw-r--r--include/linux/lm95245.h37
-rw-r--r--include/linux/mfd/stmpe.h32
-rw-r--r--include/linux/mfd/tps6586x.h10
-rw-r--r--include/linux/mmc/sdhci.h2
-rw-r--r--include/linux/platform_data/tegra_usb.h1
-rw-r--r--kernel/workqueue.c8
-rw-r--r--sound/pci/hda/hda_eld.c6
-rw-r--r--sound/pci/hda/patch_hdmi.c4
-rw-r--r--sound/pci/hda/patch_realtek.c11
-rw-r--r--sound/soc/codecs/sgtl5000.c86
-rw-r--r--sound/soc/codecs/sgtl5000.h2
-rw-r--r--sound/soc/tegra/Kconfig34
-rw-r--r--sound/soc/tegra/Makefile6
-rw-r--r--sound/soc/tegra/colibri_t20.c393
-rw-r--r--sound/soc/tegra/colibri_t30.c412
-rw-r--r--sound/soc/tegra/tegra20_ac97.c651
-rw-r--r--sound/soc/tegra/tegra20_ac97.h43
-rw-r--r--sound/soc/tegra/tegra_pcm.c37
191 files changed, 27529 insertions, 2275 deletions
diff --git a/arch/arm/configs/apalis_t30_defconfig b/arch/arm/configs/apalis_t30_defconfig
new file mode 100644
index 000000000000..d1c2e57384a9
--- /dev/null
+++ b/arch/arm/configs/apalis_t30_defconfig
@@ -0,0 +1,402 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_ELF_CORE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_PERF_EVENTS is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_ARCH_TEGRA_3x_SOC=y
+CONFIG_TEGRA_PCI=y
+CONFIG_MACH_APALIS_T30=y
+CONFIG_TEGRA_PWM=y
+CONFIG_TEGRA_EMC_SCALING_ENABLE=y
+CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
+CONFIG_USB_HOTPLUG=y
+CONFIG_TEGRA_DYNAMIC_PWRDET=y
+CONFIG_TEGRA_PLLM_RESTRICTED=y
+CONFIG_TEGRA_PREINIT_CLOCKS=y
+CONFIG_ARM_ERRATA_716044=y
+CONFIG_ARM_ERRATA_742230=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_752520=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEASPM_POWERSAVE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_PM_RUNTIME=y
+CONFIG_SUSPEND_TIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_CAN=y
+CONFIG_CAN_RAW=y
+CONFIG_CAN_BCM=y
+CONFIG_CAN_DEV=y
+CONFIG_CAN_MCP251X=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_BLUESLEEP=y
+CONFIG_CFG80211=y
+CONFIG_MAC80211=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_MISC_DEVICES=y
+CONFIG_UID_STAT=y
+CONFIG_TEGRA_CRYPTO_DEV=y
+# CONFIG_INV_SENSORS is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_ATA=y
+CONFIG_SATA_AHCI_TEGRA=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_NETDEV_1000=y
+CONFIG_IGB=y
+# CONFIG_NETDEV_10000 is not set
+# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver
+CONFIG_USB_ZD1201=m
+CONFIG_B43=m
+CONFIG_RT2X00=y
+CONFIG_RT2800USB=y
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_STMPE=y
+CONFIG_TOUCHSCREEN_FUSION_F0710A=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=9
+CONFIG_SERIAL_8250_RUNTIME_UARTS=9
+CONFIG_SERIAL_TEGRA=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_TEGRA=y
+CONFIG_SPI=y
+CONFIG_SPI_TEGRA=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SENSORS_LM95245=y
+CONFIG_SENSORS_TEGRA_TSENSOR=y
+CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_TEGRA_WATCHDOG=y
+CONFIG_MFD_TPS65910=y
+CONFIG_MFD_STMPE=y
+CONFIG_MFD_TPS6591X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
+CONFIG_REGULATOR_TPS65910=y
+CONFIG_REGULATOR_TPS62360=y
+CONFIG_REGULATOR_TPS6591X=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEOBUF2_MEMOPS=m
+CONFIG_VIDEOBUF2_DMA_NVMAP=m
+# CONFIG_TEGRA_AVP is not set
+# CONFIG_TEGRA_MEDIASERVER is not set
+CONFIG_TEGRA_NVAVP=y
+# CONFIG_TEGRA_CAMERA is not set
+# CONFIG_TEGRA_DTV is not set
+CONFIG_VIDEO_ADV7180=m
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_MAX9526=m
+CONFIG_VIDEO_TEGRA=m
+CONFIG_USB_VIDEO_CLASS=y
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_TEGRA_GRHOST=y
+CONFIG_TEGRA_DC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_TEGRA_PWM=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_HDA_INTEL=y
+CONFIG_SND_HDA_PLATFORM_DRIVER=y
+CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA=y
+# CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS is not set
+# CONFIG_SND_HDA_CODEC_ANALOG is not set
+# CONFIG_SND_HDA_CODEC_SIGMATEL is not set
+# CONFIG_SND_HDA_CODEC_VIA is not set
+# CONFIG_SND_HDA_CODEC_CIRRUS is not set
+# CONFIG_SND_HDA_CODEC_CONEXANT is not set
+# CONFIG_SND_HDA_CODEC_CA0110 is not set
+# CONFIG_SND_HDA_CODEC_CA0132 is not set
+# CONFIG_SND_HDA_CODEC_CMEDIA is not set
+# CONFIG_SND_HDA_CODEC_SI3054 is not set
+# CONFIG_SND_HDA_GENERIC is not set
+CONFIG_SND_HDA_POWER_SAVE=y
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=10
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA_COLIBRI_T30=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_ACM=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_TEGRA=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_TEGRA_OTG=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_BKOPS=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PWM=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_TEGRA=y
+CONFIG_RTC_DRV_TPS6591x=y
+CONFIG_STAGING=y
+CONFIG_IIO=y
+CONFIG_STMPE_ADC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=m
+CONFIG_PRINTK_TIME=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TEGRA_SE=y
diff --git a/arch/arm/configs/colibri_pxa_defconfig b/arch/arm/configs/colibri_pxa_defconfig
new file mode 100644
index 000000000000..8e8fe898bf15
--- /dev/null
+++ b/arch/arm/configs/colibri_pxa_defconfig
@@ -0,0 +1,340 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_ELF_CORE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_PERF_EVENTS is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_PXA=y
+CONFIG_MACH_COLIBRI=y
+CONFIG_MACH_COLIBRI300=y
+CONFIG_MACH_COLIBRI320=y
+CONFIG_MACH_LIMESTONE=y
+CONFIG_MACH_COLIBRI_EVALBOARD=y
+# CONFIG_ARM_THUMB is not set
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_PXA2XX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_FPE_NWFPE=y
+CONFIG_PM_RUNTIME=y
+CONFIG_SUSPEND_TIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_CFG80211=y
+CONFIG_MAC80211=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_LE_BYTE_SWAP=y
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PXA2XX=y
+CONFIG_MTD_BLOCK2MTD=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_PXA3xx=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_MISC_DEVICES=y
+CONFIG_UID_STAT=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+# CONFIG_SATA_PMP is not set
+# CONFIG_ATA_BMDMA is not set
+CONFIG_PATA_PCMCIA=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_PHYLIB=y
+CONFIG_NET_ETHERNET=y
+CONFIG_AX88796=y
+CONFIG_AX88796C=y
+CONFIG_DM9000=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver
+CONFIG_USB_ZD1201=m
+CONFIG_RT2X00=y
+CONFIG_RT2800USB=y
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_UCB1400=y
+CONFIG_TOUCHSCREEN_WM97XX=y
+# CONFIG_TOUCHSCREEN_WM9705 is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PXA=y
+CONFIG_SPI=y
+CONFIG_SPI_PXA2XX=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_WM97XX=y
+CONFIG_BATTERY_BQ27x00=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_SA1100_WATCHDOG=y
+CONFIG_UCB1400_CORE=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+CONFIG_USB_VIDEO_CLASS=y
+# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_PXA=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_PXA2XX_AC97=y
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+# CONFIG_SND_PCMCIA is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_PXA2XX_SOC=y
+CONFIG_SND_SOC_COLIBRI=y
+CONFIG_SND_SOC_LIMESTONE=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_ACM=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_PXA27X=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_COLIBRI_OTG=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_BKOPS=y
+CONFIG_MMC_PXA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PWM=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PXA=y
+CONFIG_STAGING=y
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_UBIFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=m
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/arm/configs/colibri_t20_android_defconfig b/arch/arm/configs/colibri_t20_android_defconfig
new file mode 100644
index 000000000000..6aa4e9ae3a1f
--- /dev/null
+++ b/arch/arm/configs/colibri_t20_android_defconfig
@@ -0,0 +1,390 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="ramdisk.cpio"
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=10
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_ELF_CORE is not set
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PCI_QUIRKS is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_MACH_COLIBRI_T20=y
+CONFIG_TEGRA_PWM=y
+CONFIG_TEGRA_EMC_SCALING_ENABLE=y
+CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
+CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND=y
+CONFIG_USB_HOTPLUG=y
+CONFIG_TEGRA_PREINIT_CLOCKS=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_SUSPEND_TIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_BLUESLEEP=y
+CONFIG_CFG80211=y
+CONFIG_MAC80211=y
+CONFIG_RFKILL=y
+CONFIG_RFKILL_GPIO=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_PROC_DEVICETREE=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND_TEGRA=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_MISC_DEVICES=y
+CONFIG_UID_STAT=y
+# CONFIG_BCM4329_RFKILL is not set
+CONFIG_TEGRA_CRYPTO_DEV=y
+# CONFIG_INV_SENSORS is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver
+CONFIG_USB_ZD1201=m
+CONFIG_RT2X00=y
+CONFIG_RT2800USB=y
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_PPP=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_WM97XX=y
+# CONFIG_TOUCHSCREEN_WM9705 is not set
+# CONFIG_TOUCHSCREEN_WM9713 is not set
+CONFIG_TOUCHSCREEN_FUSION_F0710A=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=9
+CONFIG_SERIAL_8250_RUNTIME_UARTS=9
+CONFIG_SERIAL_TEGRA=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_TEGRA=y
+CONFIG_SPI=y
+CONFIG_SPI_TEGRA=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_WM97XX=y
+CONFIG_SENSORS_LM95245=y
+CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_TEGRA_WATCHDOG=y
+CONFIG_MFD_TPS6586X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_TPS6586X=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_TEGRA_CAMERA is not set
+# CONFIG_TEGRA_DTV is not set
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_USB_VIDEO_CLASS=y
+# CONFIG_USB_GSPCA is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_TEGRA_GRHOST=y
+CONFIG_TEGRA_DC=y
+CONFIG_TEGRA_NVHDCP=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_TEGRA_PWM=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_PCI is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA_COLIBRI_T20=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_SONY=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_TEGRA=y
+CONFIG_USB_ACM=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_SERIAL_OPTION=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_TEGRA=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_COLIBRI_OTG=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PWM=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_TPS6586X=y
+CONFIG_RTC_DRV_TEGRA=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_UBIFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_FS=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TEGRA_AES=y
diff --git a/arch/arm/configs/colibri_t20_defconfig b/arch/arm/configs/colibri_t20_defconfig
new file mode 100644
index 000000000000..8fe150767638
--- /dev/null
+++ b/arch/arm/configs/colibri_t20_defconfig
@@ -0,0 +1,345 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_ELF_CORE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PCI_QUIRKS is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_MACH_COLIBRI_T20=y
+CONFIG_TEGRA_PWM=y
+CONFIG_TEGRA_EMC_SCALING_ENABLE=y
+CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
+CONFIG_USB_HOTPLUG=y
+CONFIG_TEGRA_PREINIT_CLOCKS=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_752520=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_PM_RUNTIME=y
+CONFIG_SUSPEND_TIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_BLUESLEEP=y
+CONFIG_CFG80211=y
+CONFIG_MAC80211=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND_TEGRA=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_MISC_DEVICES=y
+CONFIG_UID_STAT=y
+CONFIG_TEGRA_CRYPTO_DEV=y
+# CONFIG_INV_SENSORS is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver
+CONFIG_USB_ZD1201=m
+CONFIG_RT2X00=y
+CONFIG_RT2800USB=y
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_WM97XX=y
+# CONFIG_TOUCHSCREEN_WM9705 is not set
+# CONFIG_TOUCHSCREEN_WM9713 is not set
+CONFIG_TOUCHSCREEN_FUSION_F0710A=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=9
+CONFIG_SERIAL_8250_RUNTIME_UARTS=9
+CONFIG_SERIAL_TEGRA=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_TEGRA=y
+CONFIG_SPI=y
+CONFIG_SPI_TEGRA=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_WM97XX=y
+CONFIG_SENSORS_LM95245=y
+CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_TEGRA_WATCHDOG=y
+CONFIG_MFD_TPS6586X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
+CONFIG_REGULATOR_TPS6586X=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_TEGRA_CAMERA is not set
+# CONFIG_TEGRA_DTV is not set
+CONFIG_USB_VIDEO_CLASS=y
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_TEGRA_GRHOST=y
+CONFIG_TEGRA_DC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_TEGRA_PWM=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_PCI is not set
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA_COLIBRI_T20=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_TEGRA=y
+CONFIG_USB_ACM=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_TEGRA=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_COLIBRI_OTG=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_BKOPS=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PWM=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_TPS6586X=y
+CONFIG_RTC_DRV_TEGRA=y
+CONFIG_STAGING=y
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_UBIFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=m
+CONFIG_PRINTK_TIME=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TEGRA_AES=y
diff --git a/arch/arm/configs/colibri_t30_android_defconfig b/arch/arm/configs/colibri_t30_android_defconfig
new file mode 100644
index 000000000000..cec9d12b2c3b
--- /dev/null
+++ b/arch/arm/configs/colibri_t30_android_defconfig
@@ -0,0 +1,440 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="ramdisk.cpio"
+CONFIG_PANIC_TIMEOUT=10
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_ELF_CORE is not set
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_ARCH_TEGRA_3x_SOC=y
+CONFIG_TEGRA_PCI=y
+CONFIG_MACH_COLIBRI_T30=y
+CONFIG_TEGRA_PWM=y
+CONFIG_TEGRA_EMC_SCALING_ENABLE=y
+CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
+CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND=y
+CONFIG_USB_HOTPLUG=y
+CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ=800
+CONFIG_TEGRA_DYNAMIC_PWRDET=y
+CONFIG_TEGRA_PLLM_RESTRICTED=y
+CONFIG_TEGRA_PREINIT_CLOCKS=y
+CONFIG_TEGRA_LP1_950=y
+CONFIG_ARM_ERRATA_742230=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_752520=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEASPM_POWERSAVE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y
+CONFIG_USE_OF=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_SUSPEND_TIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_TARGET_LOG=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_BLUESLEEP=y
+CONFIG_CFG80211=m
+CONFIG_NL80211_TESTMODE=y
+CONFIG_LIB80211=m
+CONFIG_MAC80211=m
+CONFIG_RFKILL=y
+CONFIG_RFKILL_GPIO=y
+CONFIG_CAIF=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_MISC_DEVICES=y
+CONFIG_UID_STAT=y
+CONFIG_TEGRA_CRYPTO_DEV=y
+# CONFIG_INV_SENSORS is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_BCM4329=m
+CONFIG_BCM4329_FIRST_SCAN=y
+CONFIG_BCM4329_FW_PATH="/system/vendor/firmware/fw_bcm4329.bin"
+CONFIG_BCM4329_NVRAM_PATH="/system/etc/nvram_4329.txt"
+CONFIG_BCM4329_WIFI_CONTROL_FUNC=y
+CONFIG_BCM4329_HW_OOB=y
+CONFIG_BCM4329_OOB_INTR_ONLY=y
+CONFIG_BCM4329_CSCAN_ENABLE=y
+CONFIG_BCMDHD=m
+CONFIG_DHD_ENABLE_P2P=y
+CONFIG_BCMDHD_CFG80211=y
+CONFIG_BCMDHD_WIFI_CONTROL_FUNC=y
+CONFIG_BCMDHD_HW_OOB=y
+CONFIG_BCMDHD_CSCAN_ENABLE=y
+CONFIG_BCMDHD_INSMOD_NO_FW_LOAD=y
+# CONFIG_BCMDHD_CUSTOM_REGULATORY_DOMAIN is not set
+CONFIG_SD8797=m
+CONFIG_WL12XX_MENU=m
+CONFIG_WL12XX=m
+CONFIG_WL12XX_SDIO=m
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_ARMLINUX is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_USB_NET_RAW_IP=m
+CONFIG_PPP=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_STMPE=y
+CONFIG_TOUCHSCREEN_FUSION_F0710A=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_TEGRA=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_TEGRA=y
+CONFIG_SPI=y
+CONFIG_SPI_TEGRA=y
+CONFIG_SPI_SLAVE_TEGRA=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SENSORS_LM95245=y
+CONFIG_SENSORS_TEGRA_TSENSOR=y
+CONFIG_THERMAL=y
+CONFIG_MFD_TPS65910=y
+CONFIG_MFD_STMPE=y
+CONFIG_MFD_TPS6591X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_REGULATOR_TPS65910=y
+CONFIG_REGULATOR_TPS62360=y
+CONFIG_REGULATOR_TPS6591X=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_RC_CORE is not set
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_TEGRA_AVP is not set
+# CONFIG_TEGRA_MEDIASERVER is not set
+CONFIG_TEGRA_NVAVP=y
+# CONFIG_TEGRA_CAMERA is not set
+CONFIG_TEGRA_NVAVP_AUDIO=y
+CONFIG_VIDEO_OV5650=y
+CONFIG_VIDEO_OV5640=y
+CONFIG_VIDEO_OV9726=y
+CONFIG_VIDEO_OV2710=y
+CONFIG_VIDEO_AR0832=y
+CONFIG_TORCH_SSL3250A=y
+CONFIG_TORCH_TPS61050=y
+CONFIG_VIDEO_SH532U=y
+CONFIG_VIDEO_AD5816=y
+CONFIG_USB_VIDEO_CLASS=y
+# CONFIG_USB_GSPCA is not set
+# CONFIG_RADIO_ADAPTERS is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_TEGRA_GRHOST=y
+CONFIG_TEGRA_DC=y
+CONFIG_TEGRA_DSI=y
+CONFIG_TEGRA_NVHDCP=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_TEGRA_PWM=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_HDA_INTEL=y
+CONFIG_SND_HDA_PLATFORM_DRIVER=y
+CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA=y
+CONFIG_SND_HDA_POWER_SAVE=y
+CONFIG_SND_HDA_POWER_SAVE_DEFAULT=10
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA_COLIBRI_T30=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_HID_SONY=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_ACM=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_SERIAL_OPTION=y
+CONFIG_USB_SERIAL_BASEBAND=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_TEGRA=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_COLIBRI_OTG=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_BLOCK_MINORS=16
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_TPS6591x=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAILSLAB=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_FUNCTION_TRACER=y
+# CONFIG_FUNCTION_GRAPH_TRACER is not set
+CONFIG_TRACEDUMP=y
+CONFIG_TRACEDUMP_PROCFS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TEGRA_SE=y
diff --git a/arch/arm/configs/colibri_t30_defconfig b/arch/arm/configs/colibri_t30_defconfig
new file mode 100644
index 000000000000..5fd0bdc80b99
--- /dev/null
+++ b/arch/arm/configs/colibri_t30_defconfig
@@ -0,0 +1,344 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_BLK_CGROUP=y
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_ELF_CORE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PCI_QUIRKS is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_ARCH_TEGRA_3x_SOC=y
+CONFIG_MACH_COLIBRI_T30=y
+CONFIG_TEGRA_PWM=y
+CONFIG_TEGRA_EMC_SCALING_ENABLE=y
+CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
+CONFIG_USB_HOTPLUG=y
+CONFIG_TEGRA_DYNAMIC_PWRDET=y
+CONFIG_TEGRA_PLLM_RESTRICTED=y
+CONFIG_TEGRA_PREINIT_CLOCKS=y
+CONFIG_ARM_ERRATA_742230=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_752520=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_PM_RUNTIME=y
+CONFIG_SUSPEND_TIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_BLUESLEEP=y
+CONFIG_CFG80211=y
+CONFIG_MAC80211=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_MISC_DEVICES=y
+CONFIG_UID_STAT=y
+CONFIG_TEGRA_CRYPTO_DEV=y
+# CONFIG_INV_SENSORS is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# Hack to force WIRELESS_EXT required to build Redpine Signals LiteFi driver
+CONFIG_USB_ZD1201=m
+CONFIG_RT2X00=y
+CONFIG_RT2800USB=y
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_BELKIN is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_STMPE=y
+CONFIG_TOUCHSCREEN_FUSION_F0710A=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=9
+CONFIG_SERIAL_8250_RUNTIME_UARTS=9
+CONFIG_SERIAL_TEGRA=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_TEGRA=y
+CONFIG_SPI=y
+CONFIG_SPI_TEGRA=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SENSORS_LM95245=y
+CONFIG_SENSORS_TEGRA_TSENSOR=y
+CONFIG_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_TEGRA_WATCHDOG=y
+CONFIG_MFD_TPS65910=y
+CONFIG_MFD_STMPE=y
+CONFIG_MFD_TPS6591X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
+CONFIG_REGULATOR_TPS65910=y
+CONFIG_REGULATOR_TPS62360=y
+CONFIG_REGULATOR_TPS6591X=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_TEGRA_AVP is not set
+# CONFIG_TEGRA_MEDIASERVER is not set
+CONFIG_TEGRA_NVAVP=y
+# CONFIG_TEGRA_CAMERA is not set
+# CONFIG_TEGRA_DTV is not set
+CONFIG_USB_VIDEO_CLASS=y
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_TEGRA_GRHOST=y
+CONFIG_TEGRA_DC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_BACKLIGHT_TEGRA_PWM=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_PCI is not set
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA_COLIBRI_T30=y
+CONFIG_HIDRAW=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_ACM=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_TEGRA=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_COLIBRI_OTG=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_BKOPS=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PWM=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_TEGRA=y
+CONFIG_RTC_DRV_TPS6591x=y
+CONFIG_STAGING=y
+CONFIG_IIO=y
+CONFIG_STMPE_ADC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=m
+CONFIG_PRINTK_TIME=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TEGRA_SE=y
diff --git a/arch/arm/include/asm/exception.h b/arch/arm/include/asm/exception.h
new file mode 100644
index 000000000000..5abaf5bbd985
--- /dev/null
+++ b/arch/arm/include/asm/exception.h
@@ -0,0 +1,19 @@
+/*
+ * Annotations for marking C functions as exception handlers.
+ *
+ * These should only be used for C functions that are called from the low
+ * level exception entry code and not any intervening C code.
+ */
+#ifndef __ASM_ARM_EXCEPTION_H
+#define __ASM_ARM_EXCEPTION_H
+
+#include <linux/ftrace.h>
+
+#define __exception __attribute__((section(".exception.text")))
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#define __exception_irq_entry __irq_entry
+#else
+#define __exception_irq_entry __exception
+#endif
+
+#endif /* __ASM_ARM_EXCEPTION_H */
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 832888d0c20c..ed6b0499a106 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -62,13 +62,6 @@
#include <asm/outercache.h>
-#define __exception __attribute__((section(".exception.text")))
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-#define __exception_irq_entry __irq_entry
-#else
-#define __exception_irq_entry __exception
-#endif
-
struct thread_info;
struct task_struct;
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index de3dcab8610b..53919b230e8b 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -35,8 +35,8 @@
#include <linux/list.h>
#include <linux/kallsyms.h>
#include <linux/proc_fs.h>
-#include <linux/ftrace.h>
+#include <asm/exception.h>
#include <asm/system.h>
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 016473c1d794..45664df79f05 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -16,7 +16,6 @@
#include <linux/cache.h>
#include <linux/profile.h>
#include <linux/errno.h>
-#include <linux/ftrace.h>
#include <linux/mm.h>
#include <linux/err.h>
#include <linux/cpu.h>
@@ -31,6 +30,7 @@
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
+#include <asm/exception.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 2534d2a1a164..6a7e9ee75290 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -30,6 +30,7 @@
#include <linux/atomic.h>
#include <asm/cacheflush.h>
+#include <asm/exception.h>
#include <asm/system.h>
#include <asm/unistd.h>
#include <asm/traps.h>
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index cd19309fd3b8..95ed956cf123 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -235,23 +235,25 @@ endchoice
config MACH_COLIBRI
bool "Toradex Colibri PXA270"
select PXA27x
+ select HAVE_PWM
config MACH_COLIBRI_PXA270_INCOME
bool "Income s.r.o. PXA270 SBC"
depends on MACH_COLIBRI
select PXA27x
- select HAVE_PWM
config MACH_COLIBRI300
bool "Toradex Colibri PXA300/310"
select PXA3xx
select CPU_PXA300
select CPU_PXA310
+ select HAVE_PWM
config MACH_COLIBRI320
bool "Toradex Colibri PXA320"
select PXA3xx
select CPU_PXA320
+ select HAVE_PWM
config MACH_COLIBRI_EVALBOARD
bool "Toradex Colibri Evaluation Carrier Board support"
diff --git a/arch/arm/mach-pxa/colibri-evalboard.c b/arch/arm/mach-pxa/colibri-evalboard.c
index d28e802e2448..64733482f25c 100644
--- a/arch/arm/mach-pxa/colibri-evalboard.c
+++ b/arch/arm/mach-pxa/colibri-evalboard.c
@@ -46,7 +46,7 @@ static void __init colibri_mmc_init(void)
if (machine_is_colibri()) /* PXA270 Colibri */
colibri_mci_platform_data.gpio_card_detect =
GPIO0_COLIBRI_PXA270_SD_DETECT;
- if (machine_is_colibri300()) /* PXA300 Colibri */
+ else if (machine_is_colibri300()) /* PXA300 Colibri */
colibri_mci_platform_data.gpio_card_detect =
GPIO13_COLIBRI_PXA300_SD_DETECT;
else /* PXA320 Colibri */
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index b09e848eb6c6..ca6075717824 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -19,6 +19,8 @@
#include <linux/io.h>
#include <linux/irq.h>
+#include <asm/exception.h>
+
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/gpio.h>
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 8db76065ea6d..6ca839316e1a 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -29,9 +29,6 @@ config ARCH_TEGRA_2x_SOC
select USB_ULPI if USB_SUPPORT
select USB_ULPI_VIEWPORT if USB_SUPPORT
select ARM_ERRATA_742230 if SMP
- select USB_ARCH_HAS_EHCI if USB_SUPPORT
- select USB_ULPI if USB_SUPPORT
- select USB_ULPI_VIEWPORT if USB_SUPPORT
select ARCH_SUPPORTS_MSI if TEGRA_PCI
select PCI_MSI if TEGRA_PCI
select CPA
@@ -101,6 +98,12 @@ config TEGRA_IRDA
comment "Tegra board type"
+config MACH_COLIBRI_T20
+ bool "Toradex Colibri T20 module"
+ depends on ARCH_TEGRA_2x_SOC
+ help
+ Support for Toradex Colibri T20 module on Iris carrier board
+
config MACH_HARMONY
bool "Harmony board"
depends on ARCH_TEGRA_2x_SOC
@@ -166,6 +169,13 @@ config MACH_WHISTLER
help
Support for NVIDIA Whistler development platform
+config MACH_APALIS_T30
+ bool "Toradex Apalis T30 module"
+ depends on ARCH_TEGRA_3x_SOC
+ help
+ Support for Toradex Apalis T30 module on Apalis evaluation carrier
+ board
+
config MACH_ARUBA
bool "Aruba board"
depends on ARCH_TEGRA_3x_SOC
@@ -183,6 +193,12 @@ config MACH_CARDHU
help
Support for NVIDIA Cardhu development platform
+config MACH_COLIBRI_T30
+ bool "Toradex Colibri T30 module"
+ depends on ARCH_TEGRA_3x_SOC
+ help
+ Support for Toradex Colibri T30 module on Iris carrier board
+
config MACH_P1852
bool "P1852 board"
depends on ARCH_TEGRA_3x_SOC
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 85e1964a2284..4a74b6481a65 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -116,6 +116,13 @@ obj-$(CONFIG_SENSORS_TEGRA_TSENSOR) += tegra3_tsensor.o
obj-$(CONFIG_TEGRA_DYNAMIC_PWRDET) += powerdetect.o
obj-$(CONFIG_TEGRA_USB_MODEM_POWER) += tegra_usb_modem_power.o
obj-$(CONFIG_TEGRA_PCI) += pcie.o
+
+obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20.o
+obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20-memory.o
+obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20-panel.o
+obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20-pinmux.o
+obj-${CONFIG_MACH_COLIBRI_T20} += board-colibri_t20-power.o
+
obj-${CONFIG_MACH_HARMONY} += board-harmony.o
obj-${CONFIG_MACH_HARMONY} += board-harmony-kbc.o
obj-${CONFIG_MACH_HARMONY} += board-harmony-panel.o
@@ -162,6 +169,12 @@ obj-${CONFIG_MACH_WHISTLER} += board-whistler-kbc.o
obj-${CONFIG_MACH_WHISTLER} += board-whistler-baseband.o
obj-${CONFIG_MACH_WHISTLER} += board-whistler-memory.o
+obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30.o
+obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30-memory.o
+obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30-panel.o
+obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30-pinmux.o
+obj-${CONFIG_MACH_APALIS_T30} += board-apalis_t30-power.o
+
obj-${CONFIG_MACH_CARDHU} += board-cardhu.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-kbc.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-irda.o
@@ -175,6 +188,12 @@ obj-${CONFIG_MACH_CARDHU} += board-cardhu-sensors.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-memory.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-powermon.o
+obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30.o
+obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30-memory.o
+obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30-panel.o
+obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30-pinmux.o
+obj-${CONFIG_MACH_COLIBRI_T30} += board-colibri_t30-power.o
+
obj-${CONFIG_MACH_KAI} += board-touch-kai-synaptics-spi.o
obj-y += board-touch-raydium_spi.o
diff --git a/arch/arm/mach-tegra/asm_macros.h b/arch/arm/mach-tegra/asm_macros.h
index 2463d797ce39..1926418957ba 100644
--- a/arch/arm/mach-tegra/asm_macros.h
+++ b/arch/arm/mach-tegra/asm_macros.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/asm_macros.h
+ * arch/arm/mach-tegra/asm_macros.h
*
* Copyright (C) 2011 NVIDIA Corporation
*
diff --git a/arch/arm/mach-tegra/board-apalis_t30-memory.c b/arch/arm/mach-tegra/board-apalis_t30-memory.c
new file mode 100644
index 000000000000..ee3d3858e285
--- /dev/null
+++ b/arch/arm/mach-tegra/board-apalis_t30-memory.c
@@ -0,0 +1,2091 @@
+/*
+ * Copyright (C) 2013 Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "board.h"
+#include "board-apalis_t30.h"
+#include "tegra3_emc.h"
+#include "fuse.h"
+
+#if 0
+static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
+ {
+ 0x32, /* Rev 3.2 */
+ 25500, /* SDRAM frequency */
+ {
+ 0x00000001, /* EMC_RC */
+ 0x00000003, /* EMC_RFC */
+ 0x00000000, /* EMC_RAS */
+ 0x00000000, /* EMC_RP */
+ 0x00000002, /* EMC_R2W */
+ 0x0000000a, /* EMC_W2R */
+ 0x00000003, /* EMC_R2P */
+ 0x0000000b, /* EMC_W2P */
+ 0x00000000, /* EMC_RD_RCD */
+ 0x00000000, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000005, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x00000007, /* EMC_QSAFE */
+ 0x0000000c, /* EMC_RDV */
+ 0x000000bd, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x0000002f, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000002, /* EMC_PDEX2WR */
+ 0x00000002, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000007, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x00000005, /* EMC_TXSR */
+ 0x00000005, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x00000001, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x000000c3, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006288, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00080000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800211c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc084, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f108, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000168, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT */
+ 0x000c000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000280, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00030003, /* MC_EMEM_ARB_CFG */
+ 0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06020102, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x74430303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xd8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80001221, /* Mode Register 0 */
+ 0x80100003, /* Mode Register 1 */
+ 0x80200008, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 51000, /* SDRAM frequency */
+ {
+ 0x00000002, /* EMC_RC */
+ 0x00000008, /* EMC_RFC */
+ 0x00000001, /* EMC_RAS */
+ 0x00000000, /* EMC_RP */
+ 0x00000002, /* EMC_R2W */
+ 0x0000000a, /* EMC_W2R */
+ 0x00000003, /* EMC_R2P */
+ 0x0000000b, /* EMC_W2P */
+ 0x00000000, /* EMC_RD_RCD */
+ 0x00000000, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000005, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x00000007, /* EMC_QSAFE */
+ 0x0000000c, /* EMC_RDV */
+ 0x00000181, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000060, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000002, /* EMC_PDEX2WR */
+ 0x00000002, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000007, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x00000009, /* EMC_TXSR */
+ 0x00000009, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x00000002, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x0000018e, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006288, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00080000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800211c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc084, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f108, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000168, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT */
+ 0x000c000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00010003, /* MC_EMEM_ARB_CFG */
+ 0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06020102, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x73430303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xd8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80001221, /* Mode Register 0 */
+ 0x80100003, /* Mode Register 1 */
+ 0x80200008, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 102000, /* SDRAM frequency */
+ {
+ 0x00000004, /* EMC_RC */
+ 0x00000010, /* EMC_RFC */
+ 0x00000003, /* EMC_RAS */
+ 0x00000001, /* EMC_RP */
+ 0x00000002, /* EMC_R2W */
+ 0x0000000a, /* EMC_W2R */
+ 0x00000003, /* EMC_R2P */
+ 0x0000000b, /* EMC_W2P */
+ 0x00000001, /* EMC_RD_RCD */
+ 0x00000001, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000005, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x00000007, /* EMC_QSAFE */
+ 0x0000000c, /* EMC_RDV */
+ 0x00000303, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000000c0, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000002, /* EMC_PDEX2WR */
+ 0x00000002, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000007, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x00000012, /* EMC_TXSR */
+ 0x00000012, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x00000004, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x0000031c, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006288, /* EMC_FBIO_CFG5 */
+ 0x007800a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00080000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800211c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc084, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f108, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000168, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT */
+ 0x000c000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0xc0000018, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06020102, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000a0403, /* MC_EMEM_ARB_DA_COVERS */
+ 0x72830504, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xd8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80001221, /* Mode Register 0 */
+ 0x80100003, /* Mode Register 1 */
+ 0x80200008, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 204000, /* SDRAM frequency */
+ {
+ 0x00000009, /* EMC_RC */
+ 0x00000020, /* EMC_RFC */
+ 0x00000007, /* EMC_RAS */
+ 0x00000002, /* EMC_RP */
+ 0x00000002, /* EMC_R2W */
+ 0x0000000a, /* EMC_W2R */
+ 0x00000005, /* EMC_R2P */
+ 0x0000000b, /* EMC_W2P */
+ 0x00000002, /* EMC_RD_RCD */
+ 0x00000002, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000005, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x00000009, /* EMC_QSAFE */
+ 0x0000000b, /* EMC_RDV */
+ 0x00000607, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000181, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000002, /* EMC_PDEX2WR */
+ 0x00000002, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000007, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x00000023, /* EMC_TXSR */
+ 0x00000023, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x00000007, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x00000638, /* EMC_TREFBW */
+ 0x00000006, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00004288, /* EMC_FBIO_CFG5 */
+ 0x004400a4, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00080000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800211c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f108, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000168, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x000c000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000d22, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
+ 0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06020102, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000a0505, /* MC_EMEM_ARB_DA_COVERS */
+ 0x72440a06, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80001221, /* Mode Register 0 */
+ 0x80100003, /* Mode Register 1 */
+ 0x80200008, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 375000, /* SDRAM frequency */
+ {
+ 0x00000011, /* EMC_RC */
+ 0x0000003a, /* EMC_RFC */
+ 0x0000000c, /* EMC_RAS */
+ 0x00000004, /* EMC_RP */
+ 0x00000003, /* EMC_R2W */
+ 0x00000008, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x0000000a, /* EMC_W2P */
+ 0x00000004, /* EMC_RD_RCD */
+ 0x00000004, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000004, /* EMC_WDV */
+ 0x00000006, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x00000008, /* EMC_QSAFE */
+ 0x0000000d, /* EMC_RDV */
+ 0x00000b2d, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000002cb, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000008, /* EMC_PDEX2WR */
+ 0x00000008, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000007, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x00000040, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000009, /* EMC_TCKE */
+ 0x0000000c, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x00000b6d, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00007088, /* EMC_FBIO_CFG5 */
+ 0x00200084, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x0003c000, /* EMC_DLL_XFORM_DQS0 */
+ 0x0003c000, /* EMC_DLL_XFORM_DQS1 */
+ 0x0003c000, /* EMC_DLL_XFORM_DQS2 */
+ 0x0003c000, /* EMC_DLL_XFORM_DQS3 */
+ 0x0003c000, /* EMC_DLL_XFORM_DQS4 */
+ 0x0003c000, /* EMC_DLL_XFORM_DQS5 */
+ 0x0003c000, /* EMC_DLL_XFORM_DQS6 */
+ 0x0003c000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00040000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00040000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00040000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00040000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f508, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x08000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x0184000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000174b, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000b, /* MC_EMEM_ARB_CFG */
+ 0xc0000044, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000009, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06030202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000d0709, /* MC_EMEM_ARB_DA_COVERS */
+ 0x75c6110a, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0x58000000, /* EMC_FBIO_SPARE */
+ 0xff00ff88, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000521, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200000, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 400000, /* SDRAM frequency */
+ {
+ 0x00000012, /* EMC_RC */
+ 0x00000040, /* EMC_RFC */
+ 0x0000000d, /* EMC_RAS */
+ 0x00000004, /* EMC_RP */
+ 0x00000002, /* EMC_R2W */
+ 0x00000009, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x0000000c, /* EMC_W2P */
+ 0x00000004, /* EMC_RD_RCD */
+ 0x00000004, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000007, /* EMC_QUSE */
+ 0x00000005, /* EMC_QRST */
+ 0x00000008, /* EMC_QSAFE */
+ 0x0000000e, /* EMC_RDV */
+ 0x00000c2e, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x0000030b, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000008, /* EMC_PDEX2WR */
+ 0x00000008, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000008, /* EMC_AR2PDEN */
+ 0x00000011, /* EMC_RW2PDEN */
+ 0x00000046, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x0000000a, /* EMC_TCKE */
+ 0x0000000d, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x00000c6f, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00007088, /* EMC_FBIO_CFG5 */
+ 0x001c0084, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00034000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00034000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00040000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00040000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00040000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00040000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f508, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x08000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x017f000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80001941, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000c, /* MC_EMEM_ARB_CFG */
+ 0xc000004a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RP */
+ 0x0000000a, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000009, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06030202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000e070a, /* MC_EMEM_ARB_DA_COVERS */
+ 0x7547130b, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0x58000000, /* EMC_FBIO_SPARE */
+ 0xff00ff88, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000731, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200008, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 450000, /* SDRAM frequency */
+ {
+ 0x00000014, /* EMC_RC */
+ 0x00000046, /* EMC_RFC */
+ 0x0000000e, /* EMC_RAS */
+ 0x00000005, /* EMC_RP */
+ 0x00000003, /* EMC_R2W */
+ 0x00000009, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x0000000c, /* EMC_W2P */
+ 0x00000005, /* EMC_RD_RCD */
+ 0x00000005, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000007, /* EMC_QUSE */
+ 0x00000005, /* EMC_QRST */
+ 0x0000000a, /* EMC_QSAFE */
+ 0x0000000e, /* EMC_RDV */
+ 0x00000d76, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x0000035d, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000009, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000009, /* EMC_AR2PDEN */
+ 0x00000011, /* EMC_RW2PDEN */
+ 0x0000004d, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x0000000e, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x00000db6, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00007088, /* EMC_FBIO_CFG5 */
+ 0x00180084, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00022000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00022000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00022000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00022000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00022000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00022000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00022000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00022000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00030000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f508, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x08000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x0178000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80001bc0, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000d, /* MC_EMEM_ARB_CFG */
+ 0xc0000051, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RP */
+ 0x0000000b, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000009, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06030202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000f080b, /* MC_EMEM_ARB_DA_COVERS */
+ 0x70a7150c, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff8b, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000731, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200008, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 533000, /* SDRAM frequency */
+ {
+ 0x00000018, /* EMC_RC */
+ 0x00000054, /* EMC_RFC */
+ 0x00000011, /* EMC_RAS */
+ 0x00000006, /* EMC_RP */
+ 0x00000003, /* EMC_R2W */
+ 0x00000009, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x0000000d, /* EMC_W2P */
+ 0x00000006, /* EMC_RD_RCD */
+ 0x00000006, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000008, /* EMC_QUSE */
+ 0x00000006, /* EMC_QRST */
+ 0x00000008, /* EMC_QSAFE */
+ 0x00000010, /* EMC_RDV */
+ 0x00000ffd, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000003ff, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x0000000b, /* EMC_PDEX2WR */
+ 0x0000000b, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000a, /* EMC_AR2PDEN */
+ 0x00000012, /* EMC_RW2PDEN */
+ 0x0000005b, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x0000000d, /* EMC_TCKE */
+ 0x00000010, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000005, /* EMC_TCLKSTABLE */
+ 0x00000006, /* EMC_TCLKSTOP */
+ 0x0000103e, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00007088, /* EMC_FBIO_CFG5 */
+ 0x00120084, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00010000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00010000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00010000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00010000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00010000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00010000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00010000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00010000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00020000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00020000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00020000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00020000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000006a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77ffc084, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f508, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000168, /* EMC_XM2QUSEPADCTRL */
+ 0x08000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT */
+ 0x01ab000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10404, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800020ae, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000f, /* MC_EMEM_ARB_CFG */
+ 0xc0000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RP */
+ 0x0000000d, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000007, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000009, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06030202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x0010090d, /* MC_EMEM_ARB_DA_COVERS */
+ 0x7028180e, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0x00000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000941, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200008, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 667000, /* SDRAM frequency */
+ {
+ 0x0000001f, /* EMC_RC */
+ 0x00000069, /* EMC_RFC */
+ 0x00000016, /* EMC_RAS */
+ 0x00000008, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x0000000c, /* EMC_W2R */
+ 0x00000003, /* EMC_R2P */
+ 0x00000011, /* EMC_W2P */
+ 0x00000008, /* EMC_RD_RCD */
+ 0x00000008, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000007, /* EMC_WDV */
+ 0x0000000b, /* EMC_QUSE */
+ 0x00000009, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x00000011, /* EMC_RDV */
+ 0x00001412, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000504, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x0000000e, /* EMC_PDEX2WR */
+ 0x0000000e, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000c, /* EMC_AR2PDEN */
+ 0x00000016, /* EMC_RW2PDEN */
+ 0x00000072, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000010, /* EMC_TCKE */
+ 0x00000015, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000006, /* EMC_TCLKSTABLE */
+ 0x00000007, /* EMC_TCLKSTOP */
+ 0x00001453, /* EMC_TREFBW */
+ 0x0000000c, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0x40070191, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00000008, /* EMC_DLL_XFORM_DQS0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS3 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS4 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS5 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS6 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0600013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f508, /* EMC_XM2COMPPADCTRL */
+ 0x07077404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x07000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x01d6000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800028a5, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000014, /* MC_EMEM_ARB_CFG */
+ 0xc0000079, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000010, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000a, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000a, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000b, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x08040202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00140c10, /* MC_EMEM_ARB_DA_COVERS */
+ 0x734a1f11, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xf8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff01, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000b71, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200018, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 750000, /* SDRAM frequency */
+ {
+ 0x00000025, /* EMC_RC */
+ 0x0000007e, /* EMC_RFC */
+ 0x0000001a, /* EMC_RAS */
+ 0x00000009, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x0000000d, /* EMC_W2R */
+ 0x00000004, /* EMC_R2P */
+ 0x00000013, /* EMC_W2P */
+ 0x00000009, /* EMC_RD_RCD */
+ 0x00000009, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000007, /* EMC_WDV */
+ 0x0000000b, /* EMC_QUSE */
+ 0x00000009, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x00000011, /* EMC_RDV */
+ 0x0000169a, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000608, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000012, /* EMC_PDEX2WR */
+ 0x00000012, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000f, /* EMC_AR2PDEN */
+ 0x00000018, /* EMC_RW2PDEN */
+ 0x00000088, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000014, /* EMC_TCKE */
+ 0x00000018, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000007, /* EMC_TCLKSTABLE */
+ 0x00000008, /* EMC_TCLKSTOP */
+ 0x00001860, /* EMC_TREFBW */
+ 0x0000000c, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0xf0080191, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00000008, /* EMC_DLL_XFORM_DQS0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS3 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS4 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS5 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS6 */
+ 0x00000008, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ0 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ1 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ2 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0600013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x22220000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f501, /* EMC_XM2COMPPADCTRL */
+ 0x07077404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x07000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x0180000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000016, /* MC_EMEM_ARB_CFG */
+ 0xc0000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000013, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x08040202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00160d13, /* MC_EMEM_ARB_DA_COVERS */
+ 0x72ac2414, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xf8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff49, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000d71, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200018, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 800000, /* SDRAM frequency */
+ {
+ 0x00000025, /* EMC_RC */
+ 0x0000007e, /* EMC_RFC */
+ 0x0000001a, /* EMC_RAS */
+ 0x00000009, /* EMC_RP */
+ 0x00000004, /* EMC_R2W */
+ 0x0000000d, /* EMC_W2R */
+ 0x00000004, /* EMC_R2P */
+ 0x00000013, /* EMC_W2P */
+ 0x00000009, /* EMC_RD_RCD */
+ 0x00000009, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000007, /* EMC_WDV */
+ 0x0000000b, /* EMC_QUSE */
+ 0x00000009, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x00000011, /* EMC_RDV */
+ 0x00001820, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000608, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000012, /* EMC_PDEX2WR */
+ 0x00000012, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000f, /* EMC_AR2PDEN */
+ 0x00000018, /* EMC_RW2PDEN */
+ 0x00000088, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000014, /* EMC_TCKE */
+ 0x00000018, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000007, /* EMC_TCLKSTABLE */
+ 0x00000008, /* EMC_TCLKSTOP */
+ 0x00001860, /* EMC_TREFBW */
+ 0x0000000c, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0xf0070191, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x0000800a, /* EMC_DLL_XFORM_DQS0 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS1 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS2 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS3 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS4 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS5 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS6 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x007fc00a, /* EMC_DLL_XFORM_DQ0 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQ1 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQ2 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0600013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x22220000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f501, /* EMC_XM2COMPPADCTRL */
+ 0x07077404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x07000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x0180000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000018, /* MC_EMEM_ARB_CFG */
+ 0xc0000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000013, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000b, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x08040202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00160d13, /* MC_EMEM_ARB_DA_COVERS */
+ 0x72ac2414, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xf8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff49, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000d71, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200018, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 900000, /* SDRAM frequency */
+ {
+ 0x0000002a, /* EMC_RC */
+ 0x0000008e, /* EMC_RFC */
+ 0x0000001e, /* EMC_RAS */
+ 0x0000000b, /* EMC_RP */
+ 0x00000006, /* EMC_R2W */
+ 0x0000000f, /* EMC_W2R */
+ 0x00000005, /* EMC_R2P */
+ 0x00000016, /* EMC_W2P */
+ 0x0000000b, /* EMC_RD_RCD */
+ 0x0000000b, /* EMC_WR_RCD */
+ 0x00000004, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000008, /* EMC_WDV */
+ 0x0000000d, /* EMC_QUSE */
+ 0x0000000b, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x00000014, /* EMC_RDV */
+ 0x00001b2c, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000006cb, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000004, /* EMC_PDEX2WR */
+ 0x00000014, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000011, /* EMC_AR2PDEN */
+ 0x0000001b, /* EMC_RW2PDEN */
+ 0x00000099, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000006, /* EMC_TCKE */
+ 0x0000001b, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000008, /* EMC_TCLKSTABLE */
+ 0x00000009, /* EMC_TCLKSTOP */
+ 0x00001b6c, /* EMC_TREFBW */
+ 0x0000000e, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0xf0040191, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x0000800a, /* EMC_DLL_XFORM_DQS0 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS1 */
+ 0x007fc00a, /* EMC_DLL_XFORM_DQS2 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS3 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS4 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS5 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS6 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQS7 */
+ 0x0001c000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x0001c000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x0001c000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x0001c000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x0001c000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x0001c000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x0001c000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x0001c000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x007fc00a, /* EMC_DLL_XFORM_DQ0 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQ1 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQ2 */
+ 0x0000000a, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0600013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x22220000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f501, /* EMC_XM2COMPPADCTRL */
+ 0x07077404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x07000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000120, /* EMC_ZCAL_WAIT_CNT */
+ 0x0128000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000367d, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000001b, /* MC_EMEM_ARB_CFG */
+ 0xc00000a2, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000016, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000e, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000d, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000e, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000009, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x09050202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x001a1016, /* MC_EMEM_ARB_DA_COVERS */
+ 0x714e2917, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff4b, /* EMC_CFG_RSV */
+ },
+ 0x00000048, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000f15, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200020, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+};
+#endif
+
+static const struct tegra_emc_table apalis_t30_emc_tables_mt41k256m16re_15e[] = {
+//25.5, 51, 102
+ {
+ 0x32, /* Rev 3.2 */
+//204 MHz crashes
+ 200000, /* SDRAM frequency [kHz] */
+ {
+ 0x0000000a, /* EmcRc */
+ 0x00000033, /* EmcRfc */
+ 0x00000007, /* EmcRas */
+ 0x00000002, /* EmcRp */
+ 0x00000003, /* EmcR2w */
+ 0x00000009, /* EmcW2r */
+ 0x00000005, /* EmcR2p */
+ 0x0000000a, /* EmcW2p */
+ 0x00000002, /* EmcRdRcd */
+ 0x00000002, /* EmcWrRcd */
+ 0x00000003, /* EmcRrd */
+ 0x00000001, /* EmcRext */
+ 0x00000000, /* EmcWext */
+ 0x00000004, /* EmcWdv */
+ 0x00000005, /* EmcQUse */
+ 0x00000004, /* EmcQRst */
+ 0x00000009, /* EmcQSafe */
+ 0x0000000b, /* EmcRdv */
+ 0x000005e9, /* EmcRefresh */
+ 0x00000000, /* EmcBurstRefreshNum */
+ 0x0000017a, /* EmcPreRefreshReqCnt */
+ 0x00000002, /* EmcPdEx2Wr */
+ 0x00000002, /* EmcPdEx2Rd */
+ 0x00000001, /* EmcPChg2Pden */
+ 0x00000000, /* EmcAct2Pden */
+ 0x00000007, /* EmcAr2Pden */
+ 0x0000000e, /* EmcRw2Pden */
+ 0x00000036, /* EmcTxsr */
+ 0x00000134, /* EmcTxsrDll */
+ 0x00000004, /* EmcTcke */
+ 0x0000000a, /* EmcTfaw */
+ 0x00000000, /* EmcTrpab */
+ 0x00000004, /* EmcTClkStable */
+ 0x00000005, /* EmcTClkStop */
+ 0x00000618, /* EmcTRefBw */
+ 0x00000006, /* EmcQUseExtra */
+ 0x00000004, /* EmcFbioCfg6 */
+ 0x00000000, /* EmcOdtWrite */
+ 0x00000000, /* EmcOdtRead */
+ 0x00004288, /* EmcFbioCfg5 */
+ 0x004600a4, /* EmcCfgDigDll */
+ 0x00008000, /* EmcCfgDigDllPeriod */
+ 0x00080000, /* EmcDllXformDqs0 */
+ 0x00080000, /* EmcDllXformDqs1 */
+ 0x00080000, /* EmcDllXformDqs2 */
+ 0x00080000, /* EmcDllXformDqs3 */
+ 0x00080000, /* EmcDllXformDqs4 */
+ 0x00080000, /* EmcDllXformDqs5 */
+ 0x00080000, /* EmcDllXformDqs6 */
+ 0x00080000, /* EmcDllXformDqs7 */
+ 0x00000000, /* EmcDllXformQUse0 */
+ 0x00000000, /* EmcDllXformQUse1 */
+ 0x00000000, /* EmcDllXformQUse2 */
+ 0x00000000, /* EmcDllXformQUse3 */
+ 0x00000000, /* EmcDllXformQUse4 */
+ 0x00000000, /* EmcDllXformQUse5 */
+ 0x00000000, /* EmcDllXformQUse6 */
+ 0x00000000, /* EmcDllXformQUse7 */
+ 0x00000000, /* EmcDliTrimTxDqs0 */
+ 0x00000000, /* EmcDliTrimTxDqs1 */
+ 0x00000000, /* EmcDliTrimTxDqs2 */
+ 0x00000000, /* EmcDliTrimTxDqs3 */
+ 0x00000000, /* EmcDliTrimTxDqs4 */
+ 0x00000000, /* EmcDliTrimTxDqs5 */
+ 0x00000000, /* EmcDliTrimTxDqs6 */
+ 0x00000000, /* EmcDliTrimTxDqs7 */
+ 0x00080000, /* EmcDllXformDq0 */
+ 0x00080000, /* EmcDllXformDq1 */
+ 0x00080000, /* EmcDllXformDq2 */
+ 0x00080000, /* EmcDllXformDq3 */
+ 0x000002a0, /* EmcXm2CmdPadCtrl */
+ 0x0800211c, /* EmcXm2DqsPadCtrl2 */
+ 0x00000000, /* EmcXm2DqPadCtrl2 */
+ 0x77fff884, /* EmcXm2ClkPadCtrl */
+ 0x01f1f108, /* EmcXm2CompPadCtrl */
+ 0x05057404, /* EmcXm2VttGenPadCtrl */
+ 0x54000007, /* EmcXm2VttGenPadCtrl2 */
+ 0x08000168, /* EmcXm2QUsePadCtrl */
+ 0x08000000, /* EmcXm2DqsPadCtrl3 */
+ 0x00000802, /* EmcCttTermCtrl */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x000c000c, /* EmcMrsWaitCnt */
+ 0x001fffff, /* EmcAutoCalInterval */
+ 0x00000000, /* EmcCtt */
+ 0x00000000, /* EmcCttDuration */
+ 0x80000ce6, /* EmcDynSelfRefControl */
+ 0x00000003, /* McEmemArbCfg */
+ 0xc0000024, /* McEmemArbOutstandingReq */
+ 0x00000001, /* McEmemArbTimingRcd */
+ 0x00000001, /* McEmemArbTimingRp */
+ 0x00000005, /* McEmemArbTimingRc */
+ 0x00000002, /* McEmemArbTimingRas */
+ 0x00000004, /* McEmemArbTimingFaw */
+ 0x00000001, /* McEmemArbTimingRrd */
+ 0x00000003, /* McEmemArbTimingRap2Pre */
+ 0x00000007, /* McEmemArbTimingWap2Pre */
+ 0x00000002, /* McEmemArbTimingR2R */
+ 0x00000001, /* McEmemArbTimingW2W */
+ 0x00000003, /* McEmemArbTimingR2W */
+ 0x00000006, /* McEmemArbTimingW2R */
+ 0x06030102, /* McEmemArbDaTurns */
+ 0x00090505, /* McEmemArbDaCovers */
+ 0x76a30906, /* McEmemArbMisc0 */
+ 0x001f0000, /* McEmemArbRing1Throttle */
+ 0xe8000000, /* EmcFbioSpare */
+ 0xff00ff00, /* EmcCfgRsv */
+ },
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000001, /* EmcCfg bit 27PERIODIC_QRST */
+ 0x80001221, /* EmcMrs */
+ 0x80100003, /* EmcEmrs */
+ 0x00000000, /* EmcMrw1 */
+ 0x00000001, /* EmcCfg bit 28 DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 300000, /* SDRAM frequency [kHz] */
+ {
+ 0x00000010, /* EmcRc */
+ 0x0000004d, /* EmcRfc */
+ 0x0000000b, /* EmcRas */
+ 0x00000003, /* EmcRp */
+ 0x00000002, /* EmcR2w */
+ 0x00000008, /* EmcW2r */
+ 0x00000003, /* EmcR2p */
+ 0x00000009, /* EmcW2p */
+ 0x00000003, /* EmcRdRcd */
+ 0x00000002, /* EmcWrRcd */
+ 0x00000002, /* EmcRrd */
+ 0x00000001, /* EmcRext */
+ 0x00000000, /* EmcWext */
+ 0x00000004, /* EmcWdv */
+ 0x00000006, /* EmcQUse */
+ 0x00000004, /* EmcQRst */
+ 0x0000000a, /* EmcQSafe */
+ 0x0000000c, /* EmcRdv */
+ 0x000008e6, /* EmcRefresh */
+ 0x00000000, /* EmcBurstRefreshNum */
+ 0x00000240, /* EmcPreRefreshReqCnt */
+ 0x0000000a, /* EmcPdEx2Wr */
+ 0x00000008, /* EmcPdEx2Rd */
+ 0x00000007, /* EmcPChg2Pden */
+ 0x00000000, /* EmcAct2Pden */
+ 0x00000007, /* EmcAr2Pden */
+ 0x0000000e, /* EmcRw2Pden */
+ 0x000000b4, /* EmcTxsr */
+ 0x00000200, /* EmcTxsrDll */
+ 0x00000004, /* EmcTcke */
+ 0x00000010, /* EmcTfaw */
+ 0x00000000, /* EmcTrpab */
+ 0x00000004, /* EmcTClkStable */
+ 0x00000005, /* EmcTClkStop */
+ 0x00000927, /* EmcTRefBw */
+ 0x00000007, /* EmcQUseExtra */
+ 0x00000004, /* EmcFbioCfg6 */
+ 0x00000000, /* EmcOdtWrite */
+ 0x00000000, /* EmcOdtRead */
+ 0x00005288, /* EmcFbioCfg5 */
+ 0x002b00a4, /* EmcCfgDigDll */
+ 0x00008000, /* EmcCfgDigDllPeriod */
+ 0x00014000, /* EmcDllXformDqs0 */
+ 0x00014000, /* EmcDllXformDqs1 */
+ 0x00014000, /* EmcDllXformDqs2 */
+ 0x00014000, /* EmcDllXformDqs3 */
+ 0x00014000, /* EmcDllXformDqs4 */
+ 0x00014000, /* EmcDllXformDqs5 */
+ 0x00014000, /* EmcDllXformDqs6 */
+ 0x00014000, /* EmcDllXformDqs7 */
+ 0x00000000, /* EmcDllXformQUse0 */
+ 0x00000000, /* EmcDllXformQUse1 */
+ 0x00000000, /* EmcDllXformQUse2 */
+ 0x00000000, /* EmcDllXformQUse3 */
+ 0x00000000, /* EmcDllXformQUse4 */
+ 0x00000000, /* EmcDllXformQUse5 */
+ 0x00000000, /* EmcDllXformQUse6 */
+ 0x00000000, /* EmcDllXformQUse7 */
+ 0x00000000, /* EmcDliTrimTxDqs0 */
+ 0x00000000, /* EmcDliTrimTxDqs1 */
+ 0x00000000, /* EmcDliTrimTxDqs2 */
+ 0x00000000, /* EmcDliTrimTxDqs3 */
+ 0x00000000, /* EmcDliTrimTxDqs4 */
+ 0x00000000, /* EmcDliTrimTxDqs5 */
+ 0x00000000, /* EmcDliTrimTxDqs6 */
+ 0x00000000, /* EmcDliTrimTxDqs7 */
+ 0x00020000, /* EmcDllXformDq0 */
+ 0x00020000, /* EmcDllXformDq1 */
+ 0x00020000, /* EmcDllXformDq2 */
+ 0x00020000, /* EmcDllXformDq3 */
+ 0x000002a0, /* EmcXm2CmdPadCtrl */
+ 0x0800211c, /* EmcXm2DqsPadCtrl2 */
+ 0x00000000, /* EmcXm2DqPadCtrl2 */
+ 0x77fff884, /* EmcXm2ClkPadCtrl */
+ 0x01f1f508, /* EmcXm2CompPadCtrl */
+ 0x05057404, /* EmcXm2VttGenPadCtrl */
+ 0x54000007, /* EmcXm2VttGenPadCtrl2 */
+ 0x08000168, /* EmcXm2QUsePadCtrl */
+ 0x08000000, /* EmcXm2DqsPadCtrl3 */
+ 0x00000802, /* EmcCttTermCtrl */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x0172000c, /* EmcMrsWaitCnt */
+ 0x001fffff, /* EmcAutoCalInterval */
+ 0x00000000, /* EmcCtt */
+ 0x00000000, /* EmcCttDuration */
+ 0x800012db, /* EmcDynSelfRefControl */
+ 0x00000004, /* McEmemArbCfg */
+ 0x80000037, /* McEmemArbOutstandingReq */
+ 0x00000001, /* McEmemArbTimingRcd */
+ 0x00000001, /* McEmemArbTimingRp */
+ 0x00000007, /* McEmemArbTimingRc */
+ 0x00000004, /* McEmemArbTimingRas */
+ 0x00000007, /* McEmemArbTimingFaw */
+ 0x00000001, /* McEmemArbTimingRrd */
+ 0x00000002, /* McEmemArbTimingRap2Pre */
+ 0x00000007, /* McEmemArbTimingWap2Pre */
+ 0x00000002, /* McEmemArbTimingR2R */
+ 0x00000002, /* McEmemArbTimingW2W */
+ 0x00000005, /* McEmemArbTimingR2W */
+ 0x00000006, /* McEmemArbTimingW2R */
+ 0x06030202, /* McEmemArbDaTurns */
+ 0x000a0507, /* McEmemArbDaCovers */
+ 0x70850e08, /* McEmemArbMisc0 */
+ 0x001f0000, /* McEmemArbRing1Throttle */
+ 0xe8000000, /* EmcFbioSpare */
+ 0xff00ff88, /* EmcCfgRsv */
+ },
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000001, /* EmcCfg bit 27PERIODIC_QRST */
+ 0x80000321, /* EmcMrs */
+ 0x80100002, /* EmcEmrs */
+ 0x00000000, /* EmcMrw1 */
+ 0x00000000, /* EmcCfg bit 28 DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 333000, /* SDRAM frequency [kHz] */
+ {
+ 0x00000010, /* EmcRc */
+ 0x00000055, /* EmcRfc */
+ 0x0000000c, /* EmcRas */
+ 0x00000004, /* EmcRp */
+ 0x00000006, /* EmcR2w */
+ 0x00000008, /* EmcW2r */
+ 0x00000003, /* EmcR2p */
+ 0x00000009, /* EmcW2p */
+ 0x00000004, /* EmcRdRcd */
+ 0x00000003, /* EmcWrRcd */
+ 0x00000002, /* EmcRrd */
+ 0x00000001, /* EmcRext */
+ 0x00000000, /* EmcWext */
+ 0x00000004, /* EmcWdv */
+ 0x00000006, /* EmcQUse */
+ 0x00000004, /* EmcQRst */
+ 0x0000000a, /* EmcQSafe */
+ 0x0000000c, /* EmcRdv */
+ 0x000009e8, /* EmcRefresh */
+ 0x00000000, /* EmcBurstRefreshNum */
+ 0x0000027e, /* EmcPreRefreshReqCnt */
+ 0x0000000a, /* EmcPdEx2Wr */
+ 0x00000008, /* EmcPdEx2Rd */
+ 0x00000007, /* EmcPChg2Pden */
+ 0x00000000, /* EmcAct2Pden */
+ 0x00000007, /* EmcAr2Pden */
+ 0x0000000e, /* EmcRw2Pden */
+ 0x000000b4, /* EmcTxsr */
+ 0x00000200, /* EmcTxsrDll */
+ 0x00000004, /* EmcTcke */
+ 0x00000015, /* EmcTfaw */
+ 0x00000000, /* EmcTrpab */
+ 0x00000004, /* EmcTClkStable */
+ 0x00000005, /* EmcTClkStop */
+ 0x00000a28, /* EmcTRefBw */
+ 0x00000000, /* EmcQUseExtra */
+ 0x00000006, /* EmcFbioCfg6 */
+ 0x00000000, /* EmcOdtWrite */
+ 0x00000000, /* EmcOdtRead */
+ 0x00007088, /* EmcFbioCfg5 */
+ 0x002600a4, /* EmcCfgDigDll */
+ 0x00008000, /* EmcCfgDigDllPeriod */
+ 0x00014000, /* EmcDllXformDqs0 */
+ 0x00014000, /* EmcDllXformDqs1 */
+ 0x00014000, /* EmcDllXformDqs2 */
+ 0x00014000, /* EmcDllXformDqs3 */
+ 0x00014000, /* EmcDllXformDqs4 */
+ 0x00014000, /* EmcDllXformDqs5 */
+ 0x00014000, /* EmcDllXformDqs6 */
+ 0x00014000, /* EmcDllXformDqs7 */
+ 0x00000000, /* EmcDllXformQUse0 */
+ 0x00000000, /* EmcDllXformQUse1 */
+ 0x00000000, /* EmcDllXformQUse2 */
+ 0x00000000, /* EmcDllXformQUse3 */
+ 0x00000000, /* EmcDllXformQUse4 */
+ 0x00000000, /* EmcDllXformQUse5 */
+ 0x00000000, /* EmcDllXformQUse6 */
+ 0x00000000, /* EmcDllXformQUse7 */
+ 0x00000000, /* EmcDliTrimTxDqs0 */
+ 0x00000000, /* EmcDliTrimTxDqs1 */
+ 0x00000000, /* EmcDliTrimTxDqs2 */
+ 0x00000000, /* EmcDliTrimTxDqs3 */
+ 0x00000000, /* EmcDliTrimTxDqs4 */
+ 0x00000000, /* EmcDliTrimTxDqs5 */
+ 0x00000000, /* EmcDliTrimTxDqs6 */
+ 0x00000000, /* EmcDliTrimTxDqs7 */
+ 0x00020000, /* EmcDllXformDq0 */
+ 0x00020000, /* EmcDllXformDq1 */
+ 0x00020000, /* EmcDllXformDq2 */
+ 0x00020000, /* EmcDllXformDq3 */
+ 0x000002a0, /* EmcXm2CmdPadCtrl */
+ 0x0800013d, /* EmcXm2DqsPadCtrl2 */
+ 0x00000000, /* EmcXm2DqPadCtrl2 */
+ 0x77fff884, /* EmcXm2ClkPadCtrl */
+ 0x01f1f508, /* EmcXm2CompPadCtrl */
+ 0x05057404, /* EmcXm2VttGenPadCtrl */
+ 0x54000007, /* EmcXm2VttGenPadCtrl2 */
+ 0x080001e8, /* EmcXm2QUsePadCtrl */
+ 0x08000021, /* EmcXm2DqsPadCtrl3 */
+ 0x00000802, /* EmcCttTermCtrl */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x016a000c, /* EmcMrsWaitCnt */
+ 0x001fffff, /* EmcAutoCalInterval */
+ 0x00000000, /* EmcCtt */
+ 0x00000000, /* EmcCttDuration */
+ 0x800014d2, /* EmcDynSelfRefControl */
+ 0x00000005, /* McEmemArbCfg */
+ 0x8000003c, /* McEmemArbOutstandingReq */
+ 0x00000001, /* McEmemArbTimingRcd */
+ 0x00000002, /* McEmemArbTimingRp */
+ 0x00000008, /* McEmemArbTimingRc */
+ 0x00000005, /* McEmemArbTimingRas */
+ 0x0000000a, /* McEmemArbTimingFaw */
+ 0x00000001, /* McEmemArbTimingRrd */
+ 0x00000002, /* McEmemArbTimingRap2Pre */
+ 0x00000007, /* McEmemArbTimingWap2Pre */
+ 0x00000002, /* McEmemArbTimingR2R */
+ 0x00000002, /* McEmemArbTimingW2W */
+ 0x00000005, /* McEmemArbTimingR2W */
+ 0x00000006, /* McEmemArbTimingW2R */
+ 0x06030202, /* McEmemArbDaTurns */
+ 0x000b0608, /* McEmemArbDaCovers */
+ 0x70850f09, /* McEmemArbMisc0 */
+ 0x001f0000, /* McEmemArbRing1Throttle */
+ 0xe8000000, /* EmcFbioSpare */
+ 0xff00ff88, /* EmcCfgRsv */
+ },
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000000, /* EmcCfg bit 27PERIODIC_QRST */
+ 0x80000321, /* EmcMrs */
+ 0x80100002, /* EmcEmrs */
+ 0x00000000, /* EmcMrw1 */
+ 0x00000000, /* EmcCfg bit 28 DYN_SELF_REF */
+ },
+//400
+ {
+ 0x32, /* Rev 3.2 */
+ 533000, /* SDRAM frequency [kHz] */
+ {
+ 0x0000001a, /* EmcRc */
+ 0x0000008b, /* EmcRfc */
+ 0x00000013, /* EmcRas */
+ 0x00000006, /* EmcRp */
+ 0x00000006, /* EmcR2w */
+ 0x0000000b, /* EmcW2r */
+ 0x00000003, /* EmcR2p */
+ 0x0000000e, /* EmcW2p */
+ 0x00000006, /* EmcRdRcd */
+ 0x00000006, /* EmcWrRcd */
+ 0x00000003, /* EmcRrd */
+ 0x00000001, /* EmcRext */
+ 0x00000000, /* EmcWext */
+ 0x00000006, /* EmcWdv */
+ 0x00000009, /* EmcQUse */
+ 0x00000007, /* EmcQRst */
+ 0x0000000a, /* EmcQSafe */
+ 0x0000000f, /* EmcRdv */
+ 0x0000100b, /* EmcRefresh */
+ 0x00000000, /* EmcBurstRefreshNum */
+ 0x000003ff, /* EmcPreRefreshReqCnt */
+ 0x0000000c, /* EmcPdEx2Wr */
+ 0x0000000c, /* EmcPdEx2Rd */
+ 0x00000007, /* EmcPChg2Pden */
+ 0x00000000, /* EmcAct2Pden */
+ 0x0000000a, /* EmcAr2Pden */
+ 0x00000012, /* EmcRw2Pden */
+ 0x000000b4, /* EmcTxsr */
+ 0x00000200, /* EmcTxsrDll */
+ 0x00000004, /* EmcTcke */
+ 0x0000001e, /* EmcTfaw */
+ 0x00000000, /* EmcTrpab */
+ 0x00000005, /* EmcTClkStable */
+ 0x00000006, /* EmcTClkStop */
+ 0x0000103e, /* EmcTRefBw */
+ 0x00000000, /* EmcQUseExtra */
+ 0x00000006, /* EmcFbioCfg6 */
+ 0x00000000, /* EmcOdtWrite */
+ 0x00000000, /* EmcOdtRead */
+ 0x00007088, /* EmcFbioCfg5 */
+ 0xf0120091, /* EmcCfgDigDll */
+ 0x00008000, /* EmcCfgDigDllPeriod */
+ 0x0000000a, /* EmcDllXformDqs0 */
+ 0x0000000a, /* EmcDllXformDqs1 */
+ 0x0000000a, /* EmcDllXformDqs2 */
+ 0x0000000a, /* EmcDllXformDqs3 */
+ 0x0000000a, /* EmcDllXformDqs4 */
+ 0x0000000a, /* EmcDllXformDqs5 */
+ 0x0000000a, /* EmcDllXformDqs6 */
+ 0x0000000a, /* EmcDllXformDqs7 */
+ 0x00000000, /* EmcDllXformQUse0 */
+ 0x00000000, /* EmcDllXformQUse1 */
+ 0x00000000, /* EmcDllXformQUse2 */
+ 0x00000000, /* EmcDllXformQUse3 */
+ 0x00000000, /* EmcDllXformQUse4 */
+ 0x00000000, /* EmcDllXformQUse5 */
+ 0x00000000, /* EmcDllXformQUse6 */
+ 0x00000000, /* EmcDllXformQUse7 */
+ 0x00000000, /* EmcDliTrimTxDqs0 */
+ 0x00000000, /* EmcDliTrimTxDqs1 */
+ 0x00000000, /* EmcDliTrimTxDqs2 */
+ 0x00000000, /* EmcDliTrimTxDqs3 */
+ 0x00000000, /* EmcDliTrimTxDqs4 */
+ 0x00000000, /* EmcDliTrimTxDqs5 */
+ 0x00000000, /* EmcDliTrimTxDqs6 */
+ 0x00000000, /* EmcDliTrimTxDqs7 */
+ 0x0000000a, /* EmcDllXformDq0 */
+ 0x0000000a, /* EmcDllXformDq1 */
+ 0x0000000a, /* EmcDllXformDq2 */
+ 0x0000000a, /* EmcDllXformDq3 */
+ 0x000002a0, /* EmcXm2CmdPadCtrl */
+ 0x0800013d, /* EmcXm2DqsPadCtrl2 */
+ 0x00000000, /* EmcXm2DqPadCtrl2 */
+ 0x77fff884, /* EmcXm2ClkPadCtrl */
+ 0x01f1f508, /* EmcXm2CompPadCtrl */
+ 0x05057404, /* EmcXm2VttGenPadCtrl */
+ 0x54000007, /* EmcXm2VttGenPadCtrl2 */
+ 0x080001e8, /* EmcXm2QUsePadCtrl */
+ 0x08000021, /* EmcXm2DqsPadCtrl3 */
+ 0x00000802, /* EmcCttTermCtrl */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x016b000c, /* EmcMrsWaitCnt */
+ 0x001fffff, /* EmcAutoCalInterval */
+ 0x00000000, /* EmcCtt */
+ 0x00000000, /* EmcCttDuration */
+ 0x800020ae, /* EmcDynSelfRefControl */
+ 0x00000008, /* McEmemArbCfg */
+ 0x80000060, /* McEmemArbOutstandingReq */
+ 0x00000002, /* McEmemArbTimingRcd */
+ 0x00000003, /* McEmemArbTimingRp */
+ 0x0000000d, /* McEmemArbTimingRc */
+ 0x00000008, /* McEmemArbTimingRas */
+ 0x0000000f, /* McEmemArbTimingFaw */
+ 0x00000002, /* McEmemArbTimingRrd */
+ 0x00000002, /* McEmemArbTimingRap2Pre */
+ 0x00000009, /* McEmemArbTimingWap2Pre */
+ 0x00000002, /* McEmemArbTimingR2R */
+ 0x00000002, /* McEmemArbTimingW2W */
+ 0x00000005, /* McEmemArbTimingR2W */
+ 0x00000006, /* McEmemArbTimingW2R */
+ 0x06030202, /* McEmemArbDaTurns */
+ 0x000f080d, /* McEmemArbDaCovers */
+ 0x70c8180e, /* McEmemArbMisc0 */
+ 0x001f0000, /* McEmemArbRing1Throttle */
+ 0xe8000000, /* EmcFbioSpare */
+ 0xff00ff88, /* EmcCfgRsv */
+ },
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000000, /* EmcCfg bit 27PERIODIC_QRST */
+ 0x80000931, /* EmcMrs */
+ 0x80100002, /* EmcEmrs */
+ 0x00000000, /* EmcMrw1 */
+ 0x00000000, /* EmcCfg bit 28 DYN_SELF_REF */
+ },
+#if 0
+ {
+ 0x32, /* Rev 3.2 */
+ 667000, /* SDRAM frequency [kHz] */
+ {
+ 0x0000001f, /* EmcRc */
+ 0x000000ac, /* EmcRfc */
+ 0x00000016, /* EmcRas */
+ 0x00000007, /* EmcRp */
+ 0x00000006, /* EmcR2w */
+ 0x0000000b, /* EmcW2r */
+ 0x00000003, /* EmcR2p */
+ 0x00000010, /* EmcW2p */
+ 0x00000007, /* EmcRdRcd */
+ 0x00000007, /* EmcWrRcd */
+ 0x00000003, /* EmcRrd */
+ 0x00000001, /* EmcRext */
+ 0x00000000, /* EmcWext */
+ 0x00000006, /* EmcWdv */
+ 0x00000009, /* EmcQUse */
+ 0x00000007, /* EmcQRst */
+ 0x0000000a, /* EmcQSafe */
+ 0x0000000f, /* EmcRdv */
+ 0x00001410, /* EmcRefresh */
+ 0x00000000, /* EmcBurstRefreshNum */
+ 0x00000504, /* EmcPreRefreshReqCnt */
+ 0x0000000e, /* EmcPdEx2Wr */
+ 0x0000000e, /* EmcPdEx2Rd */
+ 0x00000007, /* EmcPChg2Pden */
+ 0x00000000, /* EmcAct2Pden */
+ 0x0000000c, /* EmcAr2Pden */
+ 0x00000015, /* EmcRw2Pden */
+ 0x000000b4, /* EmcTxsr */
+ 0x00000200, /* EmcTxsrDll */
+ 0x00000004, /* EmcTcke */
+ 0x0000001e, /* EmcTfaw */
+ 0x00000000, /* EmcTrpab */
+ 0x00000006, /* EmcTClkStable */
+ 0x00000007, /* EmcTClkStop */
+ 0x00001450, /* EmcTRefBw */
+ 0x0000000a, /* EmcQUseExtra */
+ 0x00000006, /* EmcFbioCfg6 */
+ 0x00000000, /* EmcOdtWrite */
+ 0x00000000, /* EmcOdtRead */
+ 0x00005088, /* EmcFbioCfg5 */
+ 0xf00b0191, /* EmcCfgDigDll */
+ 0x00008000, /* EmcCfgDigDllPeriod */
+ 0x0000000a, /* EmcDllXformDqs0 */
+ 0x0000000a, /* EmcDllXformDqs1 */
+ 0x0000000a, /* EmcDllXformDqs2 */
+ 0x0000000a, /* EmcDllXformDqs3 */
+ 0x0000000a, /* EmcDllXformDqs4 */
+ 0x0000000a, /* EmcDllXformDqs5 */
+ 0x0000000a, /* EmcDllXformDqs6 */
+ 0x0000000a, /* EmcDllXformDqs7 */
+ 0x00000000, /* EmcDllXformQUse0 */
+ 0x00000000, /* EmcDllXformQUse1 */
+ 0x00000000, /* EmcDllXformQUse2 */
+ 0x00000000, /* EmcDllXformQUse3 */
+ 0x00000000, /* EmcDllXformQUse4 */
+ 0x00000000, /* EmcDllXformQUse5 */
+ 0x00000000, /* EmcDllXformQUse6 */
+ 0x00000000, /* EmcDllXformQUse7 */
+ 0x00000000, /* EmcDliTrimTxDqs0 */
+ 0x00000000, /* EmcDliTrimTxDqs1 */
+ 0x00000000, /* EmcDliTrimTxDqs2 */
+ 0x00000000, /* EmcDliTrimTxDqs3 */
+ 0x00000000, /* EmcDliTrimTxDqs4 */
+ 0x00000000, /* EmcDliTrimTxDqs5 */
+ 0x00000000, /* EmcDliTrimTxDqs6 */
+ 0x00000000, /* EmcDliTrimTxDqs7 */
+ 0x0000000a, /* EmcDllXformDq0 */
+ 0x0000000a, /* EmcDllXformDq1 */
+ 0x0000000a, /* EmcDllXformDq2 */
+ 0x0000000a, /* EmcDllXformDq3 */
+ 0x000002a0, /* EmcXm2CmdPadCtrl */
+ 0x0800013d, /* EmcXm2DqsPadCtrl2 */
+ 0x22220000, /* EmcXm2DqPadCtrl2 */
+ 0x77fff884, /* EmcXm2ClkPadCtrl */
+ 0x01f1f508, /* EmcXm2CompPadCtrl */
+ 0x07077404, /* EmcXm2VttGenPadCtrl */
+ 0x54000000, /* EmcXm2VttGenPadCtrl2 */
+ 0x080001e8, /* EmcXm2QUsePadCtrl */
+ 0x08000021, /* EmcXm2DqsPadCtrl3 */
+ 0x00000802, /* EmcCttTermCtrl */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x0196000c, /* EmcMrsWaitCnt */
+ 0x001fffff, /* EmcAutoCalInterval */
+ 0x00000000, /* EmcCtt */
+ 0x00000000, /* EmcCttDuration */
+ 0x800028a0, /* EmcDynSelfRefControl */
+ 0x0000000a, /* McEmemArbCfg */
+ 0x80000078, /* McEmemArbOutstandingReq */
+ 0x00000003, /* McEmemArbTimingRcd */
+ 0x00000004, /* McEmemArbTimingRp */
+ 0x00000010, /* McEmemArbTimingRc */
+ 0x0000000a, /* McEmemArbTimingRas */
+ 0x0000000f, /* McEmemArbTimingFaw */
+ 0x00000002, /* McEmemArbTimingRrd */
+ 0x00000003, /* McEmemArbTimingRap2Pre */
+ 0x0000000b, /* McEmemArbTimingWap2Pre */
+ 0x00000002, /* McEmemArbTimingR2R */
+ 0x00000002, /* McEmemArbTimingW2W */
+ 0x00000004, /* McEmemArbTimingR2W */
+ 0x00000007, /* McEmemArbTimingW2R */
+ 0x07040202, /* McEmemArbDaTurns */
+ 0x00130b10, /* McEmemArbDaCovers */
+ 0x70ea1e11, /* McEmemArbMisc0 */
+ 0x001f0000, /* McEmemArbRing1Throttle */
+ 0xe8000000, /* EmcFbioSpare */
+ 0xff00ff49, /* EmcCfgRsv */
+ },
+ 0x00000040, /* EmcZcalWaitCnt */
+ 0x00020000, /* EmcZcalInterval */
+ 0x00000001, /* EmcCfg bit 27PERIODIC_QRST */
+ 0x80000b51, /* EmcMrs */
+ 0x80100002, /* EmcEmrs */
+ 0x00000000, /* EmcMrw1 */
+ 0x00000000, /* EmcCfg bit 28 DYN_SELF_REF */
+ },
+//750
+#endif
+};
+
+int apalis_t30_emc_init(void)
+{
+#if 1
+ tegra_init_emc(apalis_t30_emc_tables_mt41k256m16re_15e,
+ ARRAY_SIZE(apalis_t30_emc_tables_mt41k256m16re_15e));
+#else
+ tegra_init_emc(cardhu_emc_tables_h5tc2g_a2,
+ ARRAY_SIZE(cardhu_emc_tables_h5tc2g_a2));
+#endif
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/board-apalis_t30-panel.c b/arch/arm/mach-tegra/board-apalis_t30-panel.c
new file mode 100644
index 000000000000..1be339dce6ef
--- /dev/null
+++ b/arch/arm/mach-tegra/board-apalis_t30-panel.c
@@ -0,0 +1,514 @@
+/*
+ * arch/arm/mach-tegra/board-apalis_t30-panel.c
+ *
+ * Copyright (c) 2013, Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <asm/atomic.h>
+#include <asm/mach-types.h>
+
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/gpio.h>
+#include <linux/ion.h>
+#include <linux/nvhost.h>
+#include <linux/nvmap.h>
+#include <linux/platform_device.h>
+#include <linux/pwm_backlight.h>
+#include <linux/regulator/consumer.h>
+#include <linux/resource.h>
+#include <linux/tegra_ion.h>
+
+#include <mach/dc.h>
+#include <mach/fb.h>
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+#include <mach/smmu.h>
+
+#include "board.h"
+#include "board-apalis_t30.h"
+#include "devices.h"
+#include "gpio-names.h"
+#include "tegra3_host1x_devices.h"
+
+#define apalis_t30_bl_enb BKL1_ON
+#define apalis_t30_hdmi_hpd HDMI1_HPD
+
+static struct regulator *apalis_t30_hdmi_pll = NULL;
+static struct regulator *apalis_t30_hdmi_reg = NULL;
+
+static int apalis_t30_backlight_init(struct device *dev) {
+ int ret;
+
+ ret = gpio_request(apalis_t30_bl_enb, "BKL1_ON");
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_direction_output(apalis_t30_bl_enb, 1);
+ if (ret < 0)
+ gpio_free(apalis_t30_bl_enb);
+
+ return ret;
+};
+
+static void apalis_t30_backlight_exit(struct device *dev) {
+ gpio_set_value(apalis_t30_bl_enb, 0);
+ gpio_free(apalis_t30_bl_enb);
+}
+
+static int apalis_t30_backlight_notify(struct device *dev, int brightness)
+{
+ struct platform_pwm_backlight_data *pdata = dev->platform_data;
+
+ gpio_set_value(apalis_t30_bl_enb, !!brightness);
+
+ /* Unified TFT interface displays (e.g. EDT ET070080DH6) LEDCTRL pin
+ with inverted behaviour (e.g. 0V brightest vs. 3.3V darkest)
+ Note: brightness polarity display model specific */
+ if (brightness) return pdata->max_brightness - brightness;
+ else return brightness;
+}
+
+static int apalis_t30_disp1_check_fb(struct device *dev, struct fb_info *info);
+
+static struct platform_pwm_backlight_data apalis_t30_backlight_data = {
+ .pwm_id = 0,
+ .max_brightness = 255,
+ .dft_brightness = 127,
+ .pwm_period_ns = 1000000, /* 1 kHz */
+ .init = apalis_t30_backlight_init,
+ .exit = apalis_t30_backlight_exit,
+ .notify = apalis_t30_backlight_notify,
+ /* Only toggle backlight on fb blank notifications for disp1 */
+ .check_fb = apalis_t30_disp1_check_fb,
+};
+
+static struct platform_device apalis_t30_backlight_device = {
+ .name = "pwm-backlight",
+ .id = -1,
+ .dev = {
+ .platform_data = &apalis_t30_backlight_data,
+ },
+};
+
+static int apalis_t30_panel_enable(void)
+{
+ return 0;
+}
+
+static int apalis_t30_panel_disable(void)
+{
+ return 0;
+}
+
+#ifdef CONFIG_TEGRA_DC
+
+static int apalis_t30_hdmi_enable(void)
+{
+ int ret;
+ if (!apalis_t30_hdmi_reg) {
+ apalis_t30_hdmi_reg = regulator_get(NULL, "avdd_hdmi");
+ if (IS_ERR_OR_NULL(apalis_t30_hdmi_reg)) {
+ pr_err("hdmi: couldn't get regulator avdd_hdmi\n");
+ apalis_t30_hdmi_reg = NULL;
+ return PTR_ERR(apalis_t30_hdmi_reg);
+ }
+ }
+ ret = regulator_enable(apalis_t30_hdmi_reg);
+ if (ret < 0) {
+ pr_err("hdmi: couldn't enable regulator avdd_hdmi\n");
+ return ret;
+ }
+ if (!apalis_t30_hdmi_pll) {
+ apalis_t30_hdmi_pll = regulator_get(NULL, "avdd_hdmi_pll");
+ if (IS_ERR_OR_NULL(apalis_t30_hdmi_pll)) {
+ pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n");
+ apalis_t30_hdmi_pll = NULL;
+ regulator_put(apalis_t30_hdmi_reg);
+ apalis_t30_hdmi_reg = NULL;
+ return PTR_ERR(apalis_t30_hdmi_pll);
+ }
+ }
+ ret = regulator_enable(apalis_t30_hdmi_pll);
+ if (ret < 0) {
+ pr_err("hdmi: couldn't enable regulator avdd_hdmi_pll\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int apalis_t30_hdmi_disable(void)
+{
+ regulator_disable(apalis_t30_hdmi_reg);
+ regulator_put(apalis_t30_hdmi_reg);
+ apalis_t30_hdmi_reg = NULL;
+
+ regulator_disable(apalis_t30_hdmi_pll);
+ regulator_put(apalis_t30_hdmi_pll);
+ apalis_t30_hdmi_pll = NULL;
+ return 0;
+}
+static struct resource apalis_t30_disp1_resources[] = {
+ {
+ .name = "irq",
+ .start = INT_DISPLAY_GENERAL,
+ .end = INT_DISPLAY_GENERAL,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "regs",
+ .start = TEGRA_DISPLAY_BASE,
+ .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fbmem",
+ .start = 0, /* Filled in by apalis_t30_panel_init() */
+ .end = 0, /* Filled in by apalis_t30_panel_init() */
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource apalis_t30_disp2_resources[] = {
+ {
+ .name = "irq",
+ .start = INT_DISPLAY_B_GENERAL,
+ .end = INT_DISPLAY_B_GENERAL,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "regs",
+ .start = TEGRA_DISPLAY2_BASE,
+ .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fbmem",
+ .flags = IORESOURCE_MEM,
+ .start = 0,
+ .end = 0,
+ },
+ {
+ .name = "hdmi_regs",
+ .start = TEGRA_HDMI_BASE,
+ .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+#endif /* CONFIG_TEGRA_DC */
+
+
+#ifdef CONFIG_TEGRA_DC
+static struct tegra_fb_data apalis_t30_fb_data = {
+ .win = 0,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+static struct tegra_fb_data apalis_t30_hdmi_fb_data = {
+ .win = 0,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+static struct tegra_dc_out_pin apalis_t30_dc_out_pins[] = {
+ {
+ .name = TEGRA_DC_OUT_PIN_H_SYNC,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+ {
+ .name = TEGRA_DC_OUT_PIN_V_SYNC,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+ {
+ .name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+};
+
+static struct tegra_dc_out apalis_t30_disp1_out = {
+ .type = TEGRA_DC_OUT_RGB,
+ .parent_clk = "pll_d_out0",
+ .parent_clk_backup = "pll_d2_out0",
+
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+ .depth = 24,
+ .dither = TEGRA_DC_ORDERED_DITHER,
+
+ .default_mode = "640x480-16@60",
+
+ .out_pins = apalis_t30_dc_out_pins,
+ .n_out_pins = ARRAY_SIZE(apalis_t30_dc_out_pins),
+
+ .enable = apalis_t30_panel_enable,
+ .disable = apalis_t30_panel_disable,
+};
+
+static struct tegra_dc_out apalis_t30_disp2_out = {
+ .type = TEGRA_DC_OUT_HDMI,
+ .flags = TEGRA_DC_OUT_HOTPLUG_HIGH,
+ .parent_clk = "pll_d2_out0",
+
+ .dcc_bus = 3,
+ .hotplug_gpio = apalis_t30_hdmi_hpd,
+
+ .max_pixclock = KHZ2PICOS(148500),
+
+ .default_mode = "640x480-16@60",
+
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+
+ .enable = apalis_t30_hdmi_enable,
+ .disable = apalis_t30_hdmi_disable,
+};
+
+static struct tegra_dc_platform_data apalis_t30_disp1_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &apalis_t30_disp1_out,
+ .emc_clk_rate = 300000000,
+ .fb = &apalis_t30_fb_data,
+};
+
+static struct tegra_dc_platform_data apalis_t30_disp2_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &apalis_t30_disp2_out,
+ .fb = &apalis_t30_hdmi_fb_data,
+ .emc_clk_rate = 300000000,
+};
+
+static struct nvhost_device apalis_t30_disp1_device = {
+ .name = "tegradc",
+ .id = 0,
+ .resource = apalis_t30_disp1_resources,
+ .num_resources = ARRAY_SIZE(apalis_t30_disp1_resources),
+ .dev = {
+ .platform_data = &apalis_t30_disp1_pdata,
+ },
+};
+
+static int apalis_t30_disp1_check_fb(struct device *dev, struct fb_info *info)
+{
+ return info->device == &apalis_t30_disp1_device.dev;
+}
+
+static struct nvhost_device apalis_t30_disp2_device = {
+ .name = "tegradc",
+ .id = 1,
+ .resource = apalis_t30_disp2_resources,
+ .num_resources = ARRAY_SIZE(apalis_t30_disp2_resources),
+ .dev = {
+ .platform_data = &apalis_t30_disp2_pdata,
+ },
+};
+#else /* CONFIG_TEGRA_DC */
+static int apalis_t30_disp1_check_fb(struct device *dev, struct fb_info *info)
+{
+ return 0;
+}
+#endif /* CONFIG_TEGRA_DC */
+
+#if defined(CONFIG_TEGRA_NVMAP)
+static struct nvmap_platform_carveout apalis_t30_carveouts[] = {
+ [0] = NVMAP_HEAP_CARVEOUT_IRAM_INIT,
+ [1] = {
+ .name = "generic-0",
+ .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC,
+ .base = 0, /* Filled in by apalis_t30_panel_init() */
+ .size = 0, /* Filled in by apalis_t30_panel_init() */
+ .buddy_size = SZ_32K,
+ },
+};
+
+static struct nvmap_platform_data apalis_t30_nvmap_data = {
+ .carveouts = apalis_t30_carveouts,
+ .nr_carveouts = ARRAY_SIZE(apalis_t30_carveouts),
+};
+
+static struct platform_device apalis_t30_nvmap_device = {
+ .name = "tegra-nvmap",
+ .id = -1,
+ .dev = {
+ .platform_data = &apalis_t30_nvmap_data,
+ },
+};
+#endif /* CONFIG_TEGRA_NVMAP */
+
+#if defined(CONFIG_ION_TEGRA)
+static struct platform_device tegra_iommu_device = {
+ .name = "tegra_iommu_device",
+ .id = -1,
+ .dev = {
+ .platform_data = (void *)((1 << HWGRP_COUNT) - 1),
+ },
+};
+
+static struct ion_platform_data tegra_ion_data = {
+ .nr = 4,
+ .heaps = {
+ {
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .id = TEGRA_ION_HEAP_CARVEOUT,
+ .name = "carveout",
+ .base = 0,
+ .size = 0,
+ },
+ {
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .id = TEGRA_ION_HEAP_IRAM,
+ .name = "iram",
+ .base = TEGRA_IRAM_BASE + TEGRA_RESET_HANDLER_SIZE,
+ .size = TEGRA_IRAM_SIZE - TEGRA_RESET_HANDLER_SIZE,
+ },
+ {
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .id = TEGRA_ION_HEAP_VPR,
+ .name = "vpr",
+ .base = 0,
+ .size = 0,
+ },
+ {
+ .type = ION_HEAP_TYPE_IOMMU,
+ .id = TEGRA_ION_HEAP_IOMMU,
+ .name = "iommu",
+ .base = TEGRA_SMMU_BASE,
+ .size = TEGRA_SMMU_SIZE,
+ .priv = &tegra_iommu_device.dev,
+ },
+ },
+};
+
+static struct platform_device tegra_ion_device = {
+ .name = "ion-tegra",
+ .id = -1,
+ .dev = {
+ .platform_data = &tegra_ion_data,
+ },
+};
+#endif /* CONFIG_ION_TEGRA */
+
+static struct platform_device *apalis_t30_gfx_devices[] __initdata = {
+#if defined(CONFIG_TEGRA_NVMAP)
+ &apalis_t30_nvmap_device,
+#endif
+#if defined(CONFIG_ION_TEGRA)
+ &tegra_ion_device,
+#endif
+ &tegra_pwfm0_device,
+ &apalis_t30_backlight_device,
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/* put early_suspend/late_resume handlers here for the display in order
+ * to keep the code out of the display driver, keeping it closer to upstream
+ */
+struct early_suspend apalis_t30_panel_early_suspender;
+
+static void apalis_t30_panel_early_suspend(struct early_suspend *h)
+{
+ /* power down LCD, add use a black screen for HDMI */
+ if (num_registered_fb > 0)
+ fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
+ if (num_registered_fb > 1)
+ fb_blank(registered_fb[1], FB_BLANK_NORMAL);
+}
+
+static void apalis_t30_panel_late_resume(struct early_suspend *h)
+{
+ unsigned i;
+ for (i = 0; i < num_registered_fb; i++)
+ fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
+}
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+int __init apalis_t30_panel_init(void)
+{
+ int err = 0;
+ struct resource *res;
+ void __iomem *to_io;
+
+ /* enable hdmi hotplug gpio for hotplug detection */
+ gpio_request(apalis_t30_hdmi_hpd, "HDMI1_HPD");
+ gpio_direction_input(apalis_t30_hdmi_hpd);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ apalis_t30_panel_early_suspender.suspend = apalis_t30_panel_early_suspend;
+ apalis_t30_panel_early_suspender.resume = apalis_t30_panel_late_resume;
+ apalis_t30_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ register_early_suspend(&apalis_t30_panel_early_suspender);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+#ifdef CONFIG_TEGRA_NVMAP
+ apalis_t30_carveouts[1].base = tegra_carveout_start;
+ apalis_t30_carveouts[1].size = tegra_carveout_size;
+#endif /* CONFIG_TEGRA_NVMAP */
+
+#ifdef CONFIG_ION_TEGRA
+ tegra_ion_data.heaps[0].base = tegra_carveout_start;
+ tegra_ion_data.heaps[0].size = tegra_carveout_size;
+#endif /* CONFIG_ION_TEGRA */
+
+#ifdef CONFIG_TEGRA_GRHOST
+ err = tegra3_register_host1x_devices();
+ if (err)
+ return err;
+#endif /* CONFIG_TEGRA_GRHOST */
+
+ err = platform_add_devices(apalis_t30_gfx_devices,
+ ARRAY_SIZE(apalis_t30_gfx_devices));
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
+ res = nvhost_get_resource_byname(&apalis_t30_disp1_device,
+ IORESOURCE_MEM, "fbmem");
+ res->start = tegra_fb_start;
+ res->end = tegra_fb_start + tegra_fb_size - 1;
+
+ res = nvhost_get_resource_byname(&apalis_t30_disp2_device,
+ IORESOURCE_MEM, "fbmem");
+ res->start = tegra_fb2_start;
+ res->end = tegra_fb2_start + tegra_fb2_size - 1;
+#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */
+
+ /* Make sure LVDS framebuffer is cleared. */
+ to_io = ioremap(tegra_fb_start, tegra_fb_size);
+ if (to_io) {
+ memset(to_io, 0, tegra_fb_size);
+ iounmap(to_io);
+ } else pr_err("%s: Failed to map LVDS framebuffer\n", __func__);
+
+ /* Make sure HDMI framebuffer is cleared.
+ Note: this seems to fix a tegradc.1 initialisation race in case of
+ framebuffer console as well. */
+ to_io = ioremap(tegra_fb2_start, tegra_fb2_size);
+ if (to_io) {
+ memset(to_io, 0, tegra_fb2_size);
+ iounmap(to_io);
+ } else pr_err("%s: Failed to map HDMI framebuffer\n", __func__);
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
+ if (!err)
+ err = nvhost_device_register(&apalis_t30_disp1_device);
+
+ if (!err)
+ err = nvhost_device_register(&apalis_t30_disp2_device);
+#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_NVAVP)
+ if (!err)
+ err = nvhost_device_register(&nvavp_device);
+#endif
+ return err;
+}
diff --git a/arch/arm/mach-tegra/board-apalis_t30-pinmux.c b/arch/arm/mach-tegra/board-apalis_t30-pinmux.c
new file mode 100644
index 000000000000..a04a15587129
--- /dev/null
+++ b/arch/arm/mach-tegra/board-apalis_t30-pinmux.c
@@ -0,0 +1,487 @@
+/*
+ * arch/arm/mach-tegra/board-apalis_t30-pinmux.c
+ *
+ * Copyright (C) 2013 Toradex, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <mach/pinmux.h>
+
+#include "board-apalis_t30.h"
+#include "board.h"
+#include "gpio-names.h"
+
+#define DEFAULT_DRIVE(_name) \
+ { \
+ .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
+ .hsm = TEGRA_HSM_DISABLE, \
+ .schmitt = TEGRA_SCHMITT_ENABLE, \
+ .drive = TEGRA_DRIVE_DIV_1, \
+ .pull_down = TEGRA_PULL_31, \
+ .pull_up = TEGRA_PULL_31, \
+ .slew_rising = TEGRA_SLEW_SLOWEST, \
+ .slew_falling = TEGRA_SLEW_SLOWEST, \
+ }
+
+/* Setting the drive strength of pins
+ * hsm: Enable High speed mode (ENABLE/DISABLE)
+ * Schimit: Enable/disable schimit (ENABLE/DISABLE)
+ * drive: low power mode (DIV_1, DIV_2, DIV_4, DIV_8)
+ * pulldn_drive - drive down (falling edge) - Driver Output Pull-Down drive
+ * strength code. Value from 0 to 31.
+ * pullup_drive - drive up (rising edge) - Driver Output Pull-Up drive
+ * strength code. Value from 0 to 31.
+ * pulldn_slew - Driver Output Pull-Up slew control code - 2bit code
+ * code 11 is least slewing of signal. code 00 is highest
+ * slewing of the signal.
+ * Value - FASTEST, FAST, SLOW, SLOWEST
+ * pullup_slew - Driver Output Pull-Down slew control code -
+ * code 11 is least slewing of signal. code 00 is highest
+ * slewing of the signal.
+ * Value - FASTEST, FAST, SLOW, SLOWEST
+ */
+#define SET_DRIVE(_name, _hsm, _schmitt, _drive, _pulldn_drive, _pullup_drive, _pulldn_slew, _pullup_slew) \
+ { \
+ .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
+ .hsm = TEGRA_HSM_##_hsm, \
+ .schmitt = TEGRA_SCHMITT_##_schmitt, \
+ .drive = TEGRA_DRIVE_##_drive, \
+ .pull_down = TEGRA_PULL_##_pulldn_drive, \
+ .pull_up = TEGRA_PULL_##_pullup_drive, \
+ .slew_rising = TEGRA_SLEW_##_pulldn_slew, \
+ .slew_falling = TEGRA_SLEW_##_pullup_slew, \
+ }
+
+static __initdata struct tegra_drive_pingroup_config apalis_t30_drive_pinmux[] = {
+ /* DEFAULT_DRIVE(<pin_group>), */
+
+ /* Audio codec */
+ SET_DRIVE(DAP2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* All I2C pins are driven to maximum drive strength */
+
+ /* GEN1_I2C: I2C_SDA/SCL on SODIMM pin 194/196 (e.g. RTC on carrier board) */
+ SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* DDC_CLOCK/DATA on X3 pin 15/16 (e.g. display EDID) */
+ SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and
+ touch screen controller */
+ SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* SDMMC2 */
+ SET_DRIVE(AO2, DISABLE, DISABLE, DIV_1, 46, 42, FAST, FAST),
+
+ /* eMMC on SDMMC4 */
+ SET_DRIVE(GMA, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST),
+ SET_DRIVE(GMB, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST),
+ SET_DRIVE(GMC, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST),
+ SET_DRIVE(GMD, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST),
+};
+
+#define DEFAULT_PINMUX(_pingroup, _mux, _pupd, _tri, _io) \
+ { \
+ .pingroup = TEGRA_PINGROUP_##_pingroup, \
+ .func = TEGRA_MUX_##_mux, \
+ .pupd = TEGRA_PUPD_##_pupd, \
+/* TRISTATE here means output driver is tri-stated */ \
+ .tristate = TEGRA_TRI_##_tri, \
+/* INPUT here means input driver is enabled vs. OUTPUT where it is disabled */ \
+ .io = TEGRA_PIN_##_io, \
+ .lock = TEGRA_PIN_LOCK_DEFAULT, \
+ .od = TEGRA_PIN_OD_DEFAULT, \
+ .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \
+ }
+
+#define I2C_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _od) \
+ { \
+ .pingroup = TEGRA_PINGROUP_##_pingroup, \
+ .func = TEGRA_MUX_##_mux, \
+ .pupd = TEGRA_PUPD_##_pupd, \
+ .tristate = TEGRA_TRI_##_tri, \
+ .io = TEGRA_PIN_##_io, \
+ .lock = TEGRA_PIN_LOCK_##_lock, \
+ .od = TEGRA_PIN_OD_##_od, \
+ .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \
+ }
+
+#define VI_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _ioreset) \
+ { \
+ .pingroup = TEGRA_PINGROUP_##_pingroup, \
+ .func = TEGRA_MUX_##_mux, \
+ .pupd = TEGRA_PUPD_##_pupd, \
+ .tristate = TEGRA_TRI_##_tri, \
+ .io = TEGRA_PIN_##_io, \
+ .lock = TEGRA_PIN_LOCK_##_lock, \
+ .od = TEGRA_PIN_OD_DEFAULT, \
+ .ioreset = TEGRA_PIN_IO_RESET_##_ioreset \
+ }
+
+static __initdata struct tegra_pingroup_config apalis_t30_pinmux[] = {
+ I2C_PINMUX(CAM_I2C_SCL, I2C3, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+ I2C_PINMUX(CAM_I2C_SDA, I2C3, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+ DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, NORMAL, NORMAL, OUTPUT),
+
+ DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CLK1_REQ, HDA, NORMAL, NORMAL, OUTPUT),
+
+ DEFAULT_PINMUX(CLK2_OUT, EXTPERIPH2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK2_REQ, RSVD1, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(CLK3_OUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(CLK3_REQ, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(CLK_32K_OUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(CRT_HSYNC, CRT, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CRT_VSYNC, CRT, NORMAL, NORMAL, OUTPUT),
+
+ DEFAULT_PINMUX(DAP1_DIN, HDA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DOUT, HDA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_FS, HDA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_SCLK, HDA, NORMAL, NORMAL, INPUT),
+
+//multiplexed CAN1/2_RX/TX
+ DEFAULT_PINMUX(DAP2_DIN, RSVD2, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(DAP2_DOUT, RSVD2, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(DAP2_FS, RSVD2, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(DAP2_SCLK, RSVD2, NORMAL, TRISTATE, OUTPUT),
+
+ DEFAULT_PINMUX(DAP3_DIN, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(DAP4_DIN, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(DAP4_DOUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(DAP4_FS, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(DAP4_SCLK, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ I2C_PINMUX(DDC_SCL, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+ I2C_PINMUX(DDC_SDA, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+
+ I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+ I2C_PINMUX(GEN1_I2C_SDA, I2C1, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+
+ I2C_PINMUX(GEN2_I2C_SCL, RSVD3, NORMAL, NORMAL, INPUT, DEFAULT, DISABLE),
+ I2C_PINMUX(GEN2_I2C_SDA, RSVD3, NORMAL, NORMAL, INPUT, DEFAULT, DISABLE),
+
+ DEFAULT_PINMUX(GMI_A16, SPI4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A17, SPI4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A18, SPI4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A19, SPI4, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(GMI_AD0, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD1, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD2, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD3, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD4, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD5, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD6, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD7, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD8, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD9, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD10, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD11, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD12, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD13, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD14, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_AD15, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_ADV_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_CLK, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_CS0_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_CS1_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_CS2_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_CS3_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_CS4_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_CS6_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_CS7_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_DQS, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_IORDY, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(GMI_OE_N, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_RST_N, RSVD3, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(GMI_WAIT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_WP_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GMI_WR_N, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(GPIO_PBB0, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB4, VGP4, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB5, VGP5, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB6, VGP6, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB7, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PCC1, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PCC2, RSVD1, NORMAL, NORMAL, OUTPUT),
+
+ DEFAULT_PINMUX(GPIO_PU0, GMI, PULL_DOWN, NORMAL, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GPIO_PU1, GMI, PULL_DOWN, NORMAL, OUTPUT), /* NC */
+ DEFAULT_PINMUX(GPIO_PU2, GMI, PULL_DOWN, NORMAL, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(GPIO_PU3, PWM0, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU4, PWM1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU5, PWM2, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU6, PWM3, NORMAL, NORMAL, OUTPUT),
+
+ DEFAULT_PINMUX(GPIO_PV0, RSVD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV1, RSVD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV2, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(HDMI_CEC, CEC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(HDMI_INT, RSVD0, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(JTAG_RTCK, RTCK, NORMAL, NORMAL, OUTPUT),
+
+//multiplexed OWR
+ DEFAULT_PINMUX(KB_COL0, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_COL1, KBC, NORMAL, NORMAL, INPUT),
+
+//multiplexed VI_PCLK, VI_VSYNC and VI_HSYNC
+ DEFAULT_PINMUX(KB_COL2, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL3, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL4, KBC, NORMAL, TRISTATE, INPUT),
+
+//multiplexed VI_D11
+ DEFAULT_PINMUX(KB_COL5, KBC, NORMAL, NORMAL, INPUT),
+//multiplexed VI_D10
+ DEFAULT_PINMUX(KB_COL6, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_COL7, KBC, NORMAL, NORMAL, INPUT),
+
+//multiplexed VI_D2, VI_D3, VI_D4, VI_D5, VI_D6, VI_D7, VI_D8 and VI_D9
+ DEFAULT_PINMUX(KB_ROW0, RSVD2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW1, RSVD2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW2, RSVD2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW3, RSVD2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW4, RSVD3, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW5, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW6, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW7, KBC, NORMAL, TRISTATE, INPUT),
+
+//multiplexed VI_D0
+ DEFAULT_PINMUX(KB_ROW8, KBC, NORMAL, NORMAL, INPUT),
+//multiplexed VI_D1
+ DEFAULT_PINMUX(KB_ROW9, KBC, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(KB_ROW10, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW11, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW13, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW14, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW15, KBC, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(LCD_CS0_N, SPI5, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(LCD_CS1_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(LCD_D0, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D1, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D2, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D3, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D4, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D5, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D6, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D7, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D9, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D10, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D11, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D12, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D13, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D14, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D15, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D16, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D17, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D18, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D19, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D20, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D21, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D22, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D23, DISPLAYA, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(LCD_DC0, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(LCD_DC1, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_DE, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_HSYNC, DISPLAYA, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(LCD_M1, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(LCD_PCLK, DISPLAYA, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(LCD_PWR0, DISPLAYB, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(LCD_PWR1, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(LCD_PWR2, RSVD, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(LCD_SCK, SPI5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_SDIN, SPI5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_SDOUT, SPI5, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(LCD_VSYNC, DISPLAYA, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(LCD_WR_N, RSVD, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+//multiplexed KB_COL0
+ DEFAULT_PINMUX(OWR, OWR, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(PEX_L0_CLKREQ_N, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L0_PRSNT_N, RSVD2, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(PEX_L0_RST_N, RSVD2, NORMAL, NORMAL, OUTPUT),
+
+ DEFAULT_PINMUX(PEX_L1_CLKREQ_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(PEX_L1_PRSNT_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(PEX_L1_RST_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(PEX_L2_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L2_PRSNT_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L2_RST_N, PCIE, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(PEX_WAKE_N, PCIE, NORMAL, NORMAL, INPUT),
+
+/* Power I2C pinmux */
+ I2C_PINMUX(PWR_I2C_SCL, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+ I2C_PINMUX(PWR_I2C_SDA, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+
+ DEFAULT_PINMUX(SDMMC1_CLK, SDMMC1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_CMD, SDMMC1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT0, SDMMC1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT1, SDMMC1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT2, SDMMC1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT3, SDMMC1, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(SDMMC3_CLK, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_CMD, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT0, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT1, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT2, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT3, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT6, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT7, SDMMC3, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(SDMMC4_CLK, SDMMC4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_CMD, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT0, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT1, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT2, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT3, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT4, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT5, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT6, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT7, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_RST_N, RSVD1, PULL_DOWN, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(SPDIF_IN, SPDIF, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPDIF_OUT, SPDIF, NORMAL, NORMAL, OUTPUT),
+
+ DEFAULT_PINMUX(SPI1_CS0_N, SPI1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_MISO, SPI1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_MOSI, SPI1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_SCK, SPI1, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(SPI2_CS0_N, SPI2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI2_CS1_N, SPI2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI2_CS2_N, SPI2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI2_MISO, SPI2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI2_MOSI, SPI2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI2_SCK, SPI2, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(SYS_CLK_REQ, SYSCLK, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(UART2_CTS_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(UART2_RTS_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART2_TXD, IRDA, NORMAL, NORMAL, OUTPUT),
+
+//disable BKL1_PWM_EN# (e.g. PMIC PWM backlight enable) for now
+ DEFAULT_PINMUX(UART3_CTS_N, RSVD1, PULL_UP, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART3_RTS_N, PWM0, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART3_RXD, UARTC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_TXD, UARTC, NORMAL, NORMAL, OUTPUT),
+
+ DEFAULT_PINMUX(ULPI_CLK, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA0, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA1, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA2, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA3, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA4, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA5, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA6, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA7, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DIR, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_NXT, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_STP, UARTD, NORMAL, NORMAL, INPUT),
+
+//VI pins are all input level-shifted and multiplexed
+//unused VI pins could disable input drivers
+ VI_PINMUX(VI_D0, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D1, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D2, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D3, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D4, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D5, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D6, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D7, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D8, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D9, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D10, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D11, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_HSYNC, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ DEFAULT_PINMUX(VI_MCLK, VI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ VI_PINMUX(VI_PCLK, VI, PULL_UP, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_VSYNC, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+};
+
+#define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \
+ { \
+ .gpio_nr = _gpio, \
+ .is_input = _is_input, \
+ .value = _value, \
+ }
+
+static struct gpio_init_pin_info apalis_t30_init_gpio_mode[] = {
+};
+
+static void __init apalis_t30_gpio_init_configure(void)
+{
+ int len;
+ int i;
+ struct gpio_init_pin_info *pins_info;
+
+ len = ARRAY_SIZE(apalis_t30_init_gpio_mode);
+ pins_info = apalis_t30_init_gpio_mode;
+
+ for (i = 0; i < len; ++i) {
+ tegra_gpio_init_configure(pins_info->gpio_nr,
+ pins_info->is_input,
+ pins_info->value);
+ pins_info++;
+ }
+}
+
+int __init apalis_t30_pinmux_init(void)
+{
+ apalis_t30_gpio_init_configure();
+
+ tegra_pinmux_config_table(apalis_t30_pinmux,
+ ARRAY_SIZE(apalis_t30_pinmux));
+ tegra_drive_pinmux_config_table(apalis_t30_drive_pinmux,
+ ARRAY_SIZE(apalis_t30_drive_pinmux));
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/board-apalis_t30-power.c b/arch/arm/mach-tegra/board-apalis_t30-power.c
new file mode 100644
index 000000000000..7b2744a0fe8b
--- /dev/null
+++ b/arch/arm/mach-tegra/board-apalis_t30-power.c
@@ -0,0 +1,509 @@
+/*
+ * arch/arm/mach-tegra/board-apalis_t30-power.c
+ *
+ * Copyright (C) 2013 Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <asm/mach-types.h>
+
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/mfd/tps6591x.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/tps62360.h>
+#include <linux/regulator/tps6591x-regulator.h>
+#include <linux/resource.h>
+
+#include <mach/edp.h>
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+#include <mach/pinmux.h>
+
+#include "board-apalis_t30.h"
+#include "board.h"
+#include "gpio-names.h"
+#include "tegra3_tsensor.h"
+#include "pm.h"
+#include "wakeups.h"
+#include "wakeups-t3.h"
+
+#define PMC_CTRL 0x0
+#define PMC_CTRL_INTR_LOW (1 << 17)
+
+/* SW1: +V1.35_VDDIO_DDR */
+static struct regulator_consumer_supply tps6591x_vdd1_supply_0[] = {
+ REGULATOR_SUPPLY("mem_vddio_ddr", NULL),
+ REGULATOR_SUPPLY("t30_vddio_ddr", NULL),
+};
+
+/* SW2: +V1.05 */
+static struct regulator_consumer_supply tps6591x_vdd2_supply_0[] = {
+ REGULATOR_SUPPLY("avdd_sata", NULL),
+ REGULATOR_SUPPLY("vdd_sata", NULL),
+ REGULATOR_SUPPLY("avdd_sata_pll", NULL),
+};
+
+/* SW CTRL: +V1.0_VDD_CPU */
+static struct regulator_consumer_supply tps6591x_vddctrl_supply_0[] = {
+ REGULATOR_SUPPLY("vdd_cpu_pmu", NULL),
+ REGULATOR_SUPPLY("vdd_cpu", NULL),
+//!=vddio_sys!
+ REGULATOR_SUPPLY("vdd_sys", NULL),
+};
+
+/* SWIO: +V1.8 */
+static struct regulator_consumer_supply tps6591x_vio_supply_0[] = {
+ REGULATOR_SUPPLY("vdd_gen1v8", NULL),
+ REGULATOR_SUPPLY("avdd_usb_pll", NULL),
+ REGULATOR_SUPPLY("avdd_osc", NULL),
+ REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.3"),
+ REGULATOR_SUPPLY("pwrdet_sdmmc4", NULL),
+ REGULATOR_SUPPLY("vdd1v8_satelite", NULL),
+ REGULATOR_SUPPLY("vddio_vi", NULL),
+ REGULATOR_SUPPLY("pwrdet_vi", NULL),
+ REGULATOR_SUPPLY("ldo1", NULL),
+ REGULATOR_SUPPLY("ldo2", NULL),
+ REGULATOR_SUPPLY("ldo6", NULL),
+ REGULATOR_SUPPLY("ldo7", NULL),
+ REGULATOR_SUPPLY("ldo8", NULL),
+ REGULATOR_SUPPLY("vcore_audio", NULL),
+ REGULATOR_SUPPLY("avcore_audio", NULL),
+ REGULATOR_SUPPLY("vcore1_lpddr2", NULL),
+ REGULATOR_SUPPLY("vcom_1v8", NULL),
+ REGULATOR_SUPPLY("pmuio_1v8", NULL),
+ REGULATOR_SUPPLY("avdd_ic_usb", NULL),
+};
+
+/* unused */
+static struct regulator_consumer_supply tps6591x_ldo1_supply_0[] = {
+ REGULATOR_SUPPLY("unused_rail_ldo1", NULL),
+};
+
+/* EN_+V3.3 switching via FET: +V3.3_AUDIO_AVDD_S, +V3.3 and +V1.8_VDD_LAN
+ see also v3_3 fixed supply */
+//Apalis T30
+//+V3.3_VPP_FUSE
+//POWER_ENABLE_MOCI
+//+V3.3_TOUCH_AVDD_S
+//+V3.3_AUDIO_AVDD_S
+static struct regulator_consumer_supply tps6591x_ldo2_supply_0[] = {
+ REGULATOR_SUPPLY("en_V3_3", NULL),
+};
+
+/* +V1.2_CSI */
+static struct regulator_consumer_supply tps6591x_ldo3_supply_0[] = {
+ REGULATOR_SUPPLY("avdd_dsi_csi", NULL),
+ REGULATOR_SUPPLY("pwrdet_mipi", NULL),
+};
+
+/* +V1.2_VDD_RTC */
+static struct regulator_consumer_supply tps6591x_ldo4_supply_0[] = {
+ REGULATOR_SUPPLY("vdd_rtc", NULL),
+};
+
+/* +V2.8_AVDD_VDAC */
+//only required for analog RGB
+static struct regulator_consumer_supply tps6591x_ldo5_supply_0[] = {
+ REGULATOR_SUPPLY("avdd_vdac", NULL),
+};
+
+//Apalis T30
+/* +V1.05_AVDD_PLLE */
+static struct regulator_consumer_supply tps6591x_ldo6_supply_0[] = {
+ REGULATOR_SUPPLY("avdd_plle", NULL),
+};
+
+/* +V1.2_AVDD_PLL */
+static struct regulator_consumer_supply tps6591x_ldo7_supply_0[] = {
+ REGULATOR_SUPPLY("avdd_plla_p_c_s", NULL),
+ REGULATOR_SUPPLY("avdd_pllm", NULL),
+ REGULATOR_SUPPLY("avdd_pllu_d", NULL),
+ REGULATOR_SUPPLY("avdd_pllu_d2", NULL),
+ REGULATOR_SUPPLY("avdd_pllx", NULL),
+};
+
+/* +V1.0_VDD_DDR_HS */
+static struct regulator_consumer_supply tps6591x_ldo8_supply_0[] = {
+ REGULATOR_SUPPLY("vdd_ddr_hs", NULL),
+};
+
+#define TPS_PDATA_INIT(_name, _sname, _minmv, _maxmv, _supply_reg, _always_on, \
+ _boot_on, _apply_uv, _init_uV, _init_enable, _init_apply, _ectrl, _flags) \
+ static struct tps6591x_regulator_platform_data pdata_##_name##_##_sname = \
+ { \
+ .regulator = { \
+ .constraints = { \
+ .min_uV = (_minmv)*1000, \
+ .max_uV = (_maxmv)*1000, \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL | \
+ REGULATOR_MODE_STANDBY), \
+ .valid_ops_mask = (REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_STATUS | \
+ REGULATOR_CHANGE_VOLTAGE), \
+ .always_on = _always_on, \
+ .boot_on = _boot_on, \
+ .apply_uV = _apply_uv, \
+ }, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(tps6591x_##_name##_supply_##_sname), \
+ .consumer_supplies = tps6591x_##_name##_supply_##_sname, \
+ .supply_regulator = _supply_reg, \
+ }, \
+ .init_uV = _init_uV * 1000, \
+ .init_enable = _init_enable, \
+ .init_apply = _init_apply, \
+ .ectrl = _ectrl, \
+ .flags = _flags, \
+ }
+
+TPS_PDATA_INIT(vdd1, 0, 1350, 1350, 0, 1, 1, 1, -1, 0, 0, 0, 0);
+TPS_PDATA_INIT(vdd2, 0, 1050, 1050, 0, 1, 1, 1, -1, 0, 0, EXT_CTRL_SLEEP_OFF, 0);
+TPS_PDATA_INIT(vddctrl, 0, 800, 1300, 0, 1, 1, 0, -1, 0, 0, EXT_CTRL_EN1, 0);
+TPS_PDATA_INIT(vio, 0, 1800, 1800, 0, 1, 1, 0, -1, 0, 0, 0, 0);
+
+TPS_PDATA_INIT(ldo1, 0, 1000, 3300, tps6591x_rails(VIO), 0, 0, 0, -1, 0, 1, 0, 0);
+/* Make sure EN_+V3.3 is always on! */
+TPS_PDATA_INIT(ldo2, 0, 1200, 1200, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 1, 0, 0);
+
+TPS_PDATA_INIT(ldo3, 0, 1200, 1200, 0, 0, 0, 0, -1, 0, 0, 0, 0);
+TPS_PDATA_INIT(ldo4, 0, 900, 1400, 0, 1, 0, 0, -1, 0, 0, 0, LDO_LOW_POWER_ON_SUSPEND);
+TPS_PDATA_INIT(ldo5, 0, 2800, 2800, 0, 0, 0, 0, -1, 0, 0, 0, 0);
+/* AVDD_PLLE should be 1.05V, but ldo_6 can not be adjusted in a 50mV granularity */
+TPS_PDATA_INIT(ldo6, 0, 1000, 1100, tps6591x_rails(VIO), 0, 0, 1, -1, 0, 0, 0, 0);
+
+TPS_PDATA_INIT(ldo7, 0, 1200, 1200, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 0, EXT_CTRL_SLEEP_OFF, LDO_LOW_POWER_ON_SUSPEND);
+TPS_PDATA_INIT(ldo8, 0, 1000, 1000, tps6591x_rails(VIO), 1, 0, 0, -1, 0, 0, EXT_CTRL_SLEEP_OFF, LDO_LOW_POWER_ON_SUSPEND);
+
+#if defined(CONFIG_RTC_DRV_TPS6591x)
+static struct tps6591x_rtc_platform_data rtc_data = {
+ .irq = TPS6591X_IRQ_BASE + TPS6591X_INT_RTC_ALARM,
+ .time = {
+ .tm_year = 2000,
+ .tm_mon = 0,
+ .tm_mday = 1,
+ .tm_hour = 0,
+ .tm_min = 0,
+ .tm_sec = 0,
+ },
+};
+
+#define TPS_RTC_REG() \
+ { \
+ .id = 0, \
+ .name = "rtc_tps6591x", \
+ .platform_data = &rtc_data, \
+ }
+#endif
+
+#define TPS_REG(_id, _name, _sname) \
+ { \
+ .id = TPS6591X_ID_##_id, \
+ .name = "tps6591x-regulator", \
+ .platform_data = &pdata_##_name##_##_sname, \
+ }
+
+static struct tps6591x_subdev_info apalis_t30_tps_devs[] = {
+ TPS_REG(VDD_1, vdd1, 0),
+ TPS_REG(VDD_2, vdd2, 0),
+ TPS_REG(VDDCTRL, vddctrl, 0),
+ TPS_REG(VIO, vio, 0),
+ TPS_REG(LDO_1, ldo1, 0),
+ TPS_REG(LDO_2, ldo2, 0),
+ TPS_REG(LDO_3, ldo3, 0),
+ TPS_REG(LDO_4, ldo4, 0),
+ TPS_REG(LDO_5, ldo5, 0),
+ TPS_REG(LDO_6, ldo6, 0),
+ TPS_REG(LDO_7, ldo7, 0),
+ TPS_REG(LDO_8, ldo8, 0),
+#if defined(CONFIG_RTC_DRV_TPS6591x)
+ TPS_RTC_REG(),
+#endif
+};
+
+static struct tps6591x_sleep_keepon_data tps_slp_keepon = {
+ .clkout32k_keepon = 1,
+};
+
+static struct tps6591x_platform_data tps_platform = {
+ .irq_base = TPS6591X_IRQ_BASE,
+ .gpio_base = TPS6591X_GPIO_BASE,
+ .dev_slp_en = true,
+ .slp_keepon = &tps_slp_keepon,
+ .use_power_off = true,
+};
+
+static struct i2c_board_info __initdata apalis_t30_regulators[] = {
+ {
+ I2C_BOARD_INFO("tps6591x", 0x2D),
+//PWR_INT_IN wake18
+ .irq = INT_EXTERNAL_PMU,
+ .platform_data = &tps_platform,
+ },
+};
+
+/* TPS62362 DC-DC converter
+ SW: +V1.2_VDD_CORE */
+static struct regulator_consumer_supply tps6236x_dcdc_supply[] = {
+ REGULATOR_SUPPLY("vdd_core", NULL),
+};
+
+static struct tps62360_regulator_platform_data tps6236x_pdata = {
+ .reg_init_data = { \
+ .constraints = { \
+ .min_uV = 900000, \
+ .max_uV = 1400000, \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL | \
+ REGULATOR_MODE_STANDBY), \
+ .valid_ops_mask = (REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_STATUS | \
+ REGULATOR_CHANGE_VOLTAGE), \
+ .always_on = 1, \
+ .boot_on = 1, \
+ .apply_uV = 0, \
+ }, \
+ .num_consumer_supplies = ARRAY_SIZE(tps6236x_dcdc_supply), \
+ .consumer_supplies = tps6236x_dcdc_supply, \
+ }, \
+ .en_discharge = true, \
+ .vsel0_gpio = -1, \
+ .vsel1_gpio = -1, \
+ .vsel0_def_state = 1, \
+ .vsel1_def_state = 1, \
+};
+
+static struct i2c_board_info __initdata tps6236x_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("tps62360", 0x60),
+ .platform_data = &tps6236x_pdata,
+ },
+};
+
+/* Macro for defining fixed regulator sub device data */
+#define FIXED_SUPPLY(_name) "fixed_reg_"#_name
+#define FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, \
+ _boot_on, _gpio_nr, _active_high, _boot_state, \
+ _millivolts, _od_state) \
+ static struct regulator_init_data ri_data_##_var = \
+ { \
+ .supply_regulator = _in_supply, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(fixed_reg_##_name##_supply), \
+ .consumer_supplies = fixed_reg_##_name##_supply, \
+ .constraints = { \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL), \
+ .valid_ops_mask = (REGULATOR_CHANGE_STATUS), \
+ .always_on = _always_on, \
+ .boot_on = _boot_on, \
+ }, \
+ }; \
+ static struct fixed_voltage_config fixed_reg_##_var##_pdata = \
+ { \
+ .supply_name = FIXED_SUPPLY(_name), \
+ .microvolts = _millivolts * 1000, \
+ .gpio = _gpio_nr, \
+ .enable_high = _active_high, \
+ .enabled_at_boot = _boot_state, \
+ .init_data = &ri_data_##_var, \
+ .gpio_is_open_drain = _od_state, \
+ }; \
+ static struct platform_device fixed_reg_##_var##_dev = { \
+ .name = "reg-fixed-voltage", \
+ .id = _id, \
+ .dev = { \
+ .platform_data = &fixed_reg_##_var##_pdata, \
+ }, \
+ }
+
+#define FIXED_REG(_id, _var, _name, _in_supply, _always_on, _boot_on, \
+ _gpio_nr, _active_high, _boot_state, _millivolts) \
+ FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, _boot_on, \
+ _gpio_nr, _active_high, _boot_state, _millivolts, false)
+
+#define ADD_FIXED_REG(_name) (&fixed_reg_##_name##_dev)
+
+/* PMU GP6: EN_VDD_HDMI switching via FET: +V1.8_AVDD_HDMI_PLL and +V3.3_AVDD_HDMI */
+static struct regulator_consumer_supply fixed_reg_en_hdmi_supply[] = {
+ REGULATOR_SUPPLY("avdd_hdmi", NULL),
+ REGULATOR_SUPPLY("avdd_hdmi_pll", NULL),
+// REGULATOR_SUPPLY("vdd_3v3_hdmi_cec", NULL),
+};
+
+//EN_VDD_CORE PMIC GPIO2
+//EN_VDD_FUSE PMIC GPIO4
+//EN_VDD_HDMI PMIC GPIO6
+
+FIXED_REG(2, en_hdmi, en_hdmi, NULL, 0, 0, TPS6591X_GPIO_6, true, 1, 1800);
+
+/* +V3.3 is switched on by LDO2, As this can not be modeled we use a fixed
+ regulator without enable, 3.3V must not be switched off anyway.
++V3.3:
+VDD_DDR_RX
+VDDIO_LCD_1
+VDDIO_LCD_2
+VDDIO_CAM
+LM95245
+VDDIO_SYS_01
+VDDIO_SYS_02
+VDDIO_BB
+VDDIO_AUDIO
+VDDIO_GMI_1
+VDDIO_GMI_2
+VDDIO_GMI_3
+VDDIO_UART
+VDDIO_SDMMC1
+AVDD_USB
+VDDIO_SDMMC3
+74AVCAH164245
+VDDIO_PEX_CTL
+TPS65911 VDDIO
+MT29F16G08
+SGTL5000 VDDIO
+STMPE811
+AX88772B VCC3x
+SDIN5D2-2G VCCx */
+static struct regulator_consumer_supply fixed_reg_v3_3_supply[] = {
+ REGULATOR_SUPPLY("avdd_audio", NULL),
+ REGULATOR_SUPPLY("avdd_usb", NULL),
+ REGULATOR_SUPPLY("vddio_sd_slot", "sdhci-tegra.1"),
+ REGULATOR_SUPPLY("vddio_sys", NULL),
+ REGULATOR_SUPPLY("vddio_uart", NULL),
+ REGULATOR_SUPPLY("pwrdet_uart", NULL),
+ REGULATOR_SUPPLY("vddio_audio", NULL),
+ REGULATOR_SUPPLY("pwrdet_audio", NULL),
+ REGULATOR_SUPPLY("vddio_bb", NULL),
+ REGULATOR_SUPPLY("pwrdet_bb", NULL),
+ REGULATOR_SUPPLY("vddio_lcd_pmu", NULL),
+ REGULATOR_SUPPLY("pwrdet_lcd", NULL),
+ REGULATOR_SUPPLY("vddio_cam", NULL),
+ REGULATOR_SUPPLY("pwrdet_cam", NULL),
+ /* if this supply is defined, the sdhci driver tries
+ * to set it to 1.8V */
+// REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.1"),
+ REGULATOR_SUPPLY("pwrdet_sdmmc2", NULL),
+ REGULATOR_SUPPLY("pwrdet_sdmmc1", NULL),
+ REGULATOR_SUPPLY("pwrdet_sdmmc3", NULL),
+ REGULATOR_SUPPLY("pwrdet_pex_ctl", NULL),
+ REGULATOR_SUPPLY("pwrdet_nand", NULL),
+
+ /* SGTL5000 */
+ REGULATOR_SUPPLY("VDDA", "4-000a"),
+ REGULATOR_SUPPLY("VDDIO", "4-000a"),
+
+ REGULATOR_SUPPLY("hvdd_pex", NULL),
+ REGULATOR_SUPPLY("hvdd_sata", NULL),
+};
+
+FIXED_REG(3, v3_3, v3_3, NULL, 1, 1, -1, true, 1, 3300);
+
+/* Gpio switch regulator platform data */
+static struct platform_device *fixed_reg_devs_apalis_t30[] = {
+ ADD_FIXED_REG(en_hdmi),
+ ADD_FIXED_REG(v3_3),
+};
+
+int __init apalis_t30_regulator_init(void)
+{
+ void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+ u32 pmc_ctrl;
+
+ /* configure the power management controller to trigger PMU
+ * interrupts when low */
+
+ pmc_ctrl = readl(pmc + PMC_CTRL);
+ writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);
+
+ /* The regulator details have complete constraints */
+ regulator_has_full_constraints();
+
+ tps_platform.num_subdevs =
+ ARRAY_SIZE(apalis_t30_tps_devs);
+ tps_platform.subdevs = apalis_t30_tps_devs;
+
+ i2c_register_board_info(4, apalis_t30_regulators, 1);
+
+ /* Register the TPS6236x. */
+ pr_info("Registering the device TPS62360\n");
+ i2c_register_board_info(4, tps6236x_boardinfo, 1);
+
+ return 0;
+}
+
+int __init apalis_t30_fixed_regulator_init(void)
+{
+ return platform_add_devices(fixed_reg_devs_apalis_t30, ARRAY_SIZE(fixed_reg_devs_apalis_t30));
+}
+subsys_initcall_sync(apalis_t30_fixed_regulator_init);
+
+static void apalis_t30_board_suspend(int lp_state, enum suspend_stage stg)
+{
+ if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_SUSPEND_BEFORE_CPU))
+ tegra_console_uart_suspend();
+}
+
+static void apalis_t30_board_resume(int lp_state, enum resume_stage stg)
+{
+ if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_RESUME_AFTER_CPU))
+ tegra_console_uart_resume();
+}
+
+static struct tegra_suspend_platform_data apalis_t30_suspend_data = {
+ .cpu_timer = 2000,
+ .cpu_off_timer = 200,
+ .suspend_mode = TEGRA_SUSPEND_LP1,
+ .core_timer = 0x7e7e,
+ .core_off_timer = 0,
+ .corereq_high = true,
+ .sysclkreq_high = true,
+ .cpu_lp2_min_residency = 2000,
+ .board_suspend = apalis_t30_board_suspend,
+ .board_resume = apalis_t30_board_resume,
+};
+
+int __init apalis_t30_suspend_init(void)
+{
+ /* Make core_pwr_req to high */
+ apalis_t30_suspend_data.corereq_high = true;
+
+ /* CORE_PWR_REQ to be high required to enable the dc-dc converter tps62361x */
+ apalis_t30_suspend_data.corereq_high = true;
+
+//required?
+ apalis_t30_suspend_data.cpu_timer = 5000;
+ apalis_t30_suspend_data.cpu_off_timer = 5000;
+
+ tegra_init_suspend(&apalis_t30_suspend_data);
+ return 0;
+}
+
+#ifdef CONFIG_TEGRA_EDP_LIMITS
+int __init apalis_t30_edp_init(void)
+{
+ unsigned int regulator_mA;
+
+ regulator_mA = get_maximum_cpu_current_supported();
+ if (!regulator_mA) {
+ regulator_mA = 6000; /* regular T30/s */
+ }
+ pr_info("%s: CPU regulator %d mA\n", __func__, regulator_mA);
+
+ tegra_init_cpu_edp_limits(regulator_mA);
+ return 0;
+}
+#endif
diff --git a/arch/arm/mach-tegra/board-apalis_t30.c b/arch/arm/mach-tegra/board-apalis_t30.c
new file mode 100644
index 000000000000..f7340b91eb8d
--- /dev/null
+++ b/arch/arm/mach-tegra/board-apalis_t30.c
@@ -0,0 +1,1432 @@
+/*
+ * arch/arm/mach-tegra/board-apalis_t30.c
+ *
+ * Copyright (c) 2013 Toradex, Inc.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <linux/can/platform/mcp251x.h>
+#include <linux/clk.h>
+#include <linux/types.h> /* required by linux/gpio_keys.h */
+#include <linux/gpio_keys.h>
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/leds_pwm.h>
+#include <linux/lm95245.h>
+#include <linux/mfd/stmpe.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/spi/spi.h>
+#include <linux/spi-tegra.h>
+#include <linux/tegra_uart.h>
+
+#include <mach/io_dpd.h>
+#include <mach/pci.h>
+#include <mach/sdhci.h>
+#include <mach/tegra_asoc_pdata.h>
+#include <mach/tegra_fiq_debugger.h>
+#include <mach/thermal.h>
+#include <mach/usb_phy.h>
+#include <mach/w1.h>
+
+#include <media/soc_camera.h>
+#include <media/tegra_v4l2_camera.h>
+#include <linux/input/fusion_F0710A.h>
+
+#include "board-apalis_t30.h"
+#include "board.h"
+#include "clock.h"
+#include "devices.h"
+#include "gpio-names.h"
+#include "pm.h"
+#include "wakeups-t3.h"
+
+/* ADC */
+
+//TODO
+
+/* Audio */
+
+/* HDA */
+
+//TODO
+
+/* I2S */
+
+static struct tegra_asoc_platform_data apalis_t30_audio_sgtl5000_pdata = {
+ .gpio_spkr_en = -1,
+ .gpio_hp_det = -1,
+ .gpio_hp_mute = -1,
+ .gpio_int_mic_en = -1,
+ .gpio_ext_mic_en = -1,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 1, /* index of below registered
+ tegra_i2s_device plus one if HDA codec
+ is activated as well */
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ .is_i2s_master = 1,
+ .sample_size = 16,
+ },
+ .i2s_param[BASEBAND] = {
+ .audio_port_id = -1,
+ },
+ .i2s_param[BT_SCO] = {
+ .audio_port_id = -1,
+ },
+};
+
+static struct platform_device apalis_t30_audio_sgtl5000_device = {
+ .name = "tegra-snd-colibri_t30-sgtl5000",
+ .id = 0,
+ .dev = {
+ .platform_data = &apalis_t30_audio_sgtl5000_pdata,
+ },
+};
+
+/* Camera */
+
+#ifdef CONFIG_TEGRA_CAMERA
+static struct platform_device tegra_camera = {
+ .name = "tegra_camera",
+ .id = -1,
+};
+#endif /* CONFIG_TEGRA_CAMERA */
+
+#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE)
+static void tegra_camera_disable(struct nvhost_device *ndev)
+{
+}
+
+static int tegra_camera_enable(struct nvhost_device *ndev)
+{
+ return 0;
+}
+
+static struct tegra_camera_platform_data tegra_camera_platform_data = {
+ .disable_camera = tegra_camera_disable,
+ .enable_camera = tegra_camera_enable,
+ .flip_h = 0,
+ .flip_v = 0,
+ .port = TEGRA_CAMERA_PORT_VIP,
+};
+
+#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE)
+static struct i2c_board_info camera_i2c_max9526 = {
+ I2C_BOARD_INFO("max9526", 0x20),
+};
+
+static struct soc_camera_link iclink_max9526 = {
+ .board_info = &camera_i2c_max9526,
+ .bus_id = -1, /* This must match the .id of tegra_vi01_device */
+ .i2c_adapter_id = 2,
+};
+
+static struct platform_device soc_camera_max9526 = {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &iclink_max9526,
+ },
+};
+#endif /* CONFIG_SOC_CAMERA_MAX9526 | CONFIG_SOC_CAMERA_MAX9526_MODULE */
+
+#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE)
+static struct i2c_board_info camera_i2c_adv7180 = {
+ I2C_BOARD_INFO("adv7180", 0x21),
+};
+
+static struct soc_camera_link iclink_adv7180 = {
+ .board_info = &camera_i2c_adv7180,
+ .bus_id = -1, /* This must match the .id of tegra_vi01_device */
+ .i2c_adapter_id = 2,
+};
+
+static struct platform_device soc_camera_adv7180 = {
+ .name = "soc-camera-pdrv",
+ .id = 1,
+ .dev = {
+ .platform_data = &iclink_adv7180,
+ },
+};
+#endif /* CONFIG_VIDEO_ADV7180 | CONFIG_VIDEO_ADV7180_MODULE */
+#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */
+
+/* CAN */
+
+#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)
+static struct mcp251x_platform_data can_pdata = {
+ .oscillator_frequency = 16000000,
+ .power_enable = NULL,
+ .transceiver_enable = NULL
+};
+
+static struct spi_board_info can_board_info[] = {
+ {
+ .bus_num = 1, /* SPI2: CAN1 */
+ .chip_select = 0,
+ .max_speed_hz = 10000000,
+ .modalias = "mcp2515",
+ .platform_data = &can_pdata,
+ },
+ {
+ .bus_num = 3, /* SPI4: CAN2 */
+ .chip_select = 1,
+ .max_speed_hz = 10000000,
+ .modalias = "mcp2515",
+ .platform_data = &can_pdata,
+ },
+};
+
+static void __init apalis_t30_mcp2515_can_init(void)
+{
+ can_board_info[0].irq = gpio_to_irq(CAN1_INT);
+ can_board_info[1].irq = gpio_to_irq(CAN2_INT);
+ spi_register_board_info(can_board_info, ARRAY_SIZE(can_board_info));
+}
+#else /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+#define apalis_t30_mcp2515_can_init() do {} while (0)
+#endif /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+
+/* CEC */
+
+//TODO
+
+/* Clocks */
+static struct tegra_clk_init_table apalis_t30_clk_init_table[] __initdata = {
+ /* name parent rate enabled */
+ {"audio1", "i2s1_sync", 0, false},
+ {"audio2", "i2s2_sync", 0, false},
+ {"audio3", "i2s3_sync", 0, false},
+ {"blink", "clk_32k", 32768, true},
+ {"d_audio", "clk_m", 12000000, false},
+ {"dam0", "clk_m", 12000000, false},
+ {"dam1", "clk_m", 12000000, false},
+ {"dam2", "clk_m", 12000000, false},
+ {"hda", "pll_p", 108000000, false},
+ {"hda2codec_2x","pll_p", 48000000, false},
+ {"i2c1", "pll_p", 3200000, false},
+ {"i2c2", "pll_p", 3200000, false},
+ {"i2c3", "pll_p", 3200000, false},
+ {"i2c4", "pll_p", 3200000, false},
+ {"i2c5", "pll_p", 3200000, false},
+ {"i2s0", "pll_a_out0", 0, false},
+ {"i2s1", "pll_a_out0", 0, false},
+ {"i2s2", "pll_a_out0", 0, false},
+ {"i2s3", "pll_a_out0", 0, false},
+ {"pll_a", NULL, 564480000, true},
+ {"pll_m", NULL, 0, false},
+ {"pwm", "pll_p", 3187500, false},
+ {"spdif_out", "pll_a_out0", 0, false},
+ {"vi", "pll_p", 0, false},
+ {"vi_sensor", "pll_p", 150000000, false},
+ {NULL, NULL, 0, 0},
+};
+
+/* GPIO */
+
+static struct gpio apalis_t30_gpios[] = {
+ {APALIS_GPIO1, GPIOF_IN, "GPIO1 X1-1"},
+ {APALIS_GPIO2, GPIOF_IN, "GPIO2 X1-3"},
+ {APALIS_GPIO3, GPIOF_IN, "GPIO3 X1-5"},
+ {APALIS_GPIO4, GPIOF_IN, "GPIO4 X1-7"},
+ {APALIS_GPIO5, GPIOF_IN, "GPIO5 X1-9"},
+ {APALIS_GPIO6, GPIOF_IN, "GPIO6 X1-11"},
+ /* GPIO7 is used by PCIe driver on Evaluation board */
+/* {APALIS_GPIO7, GPIOF_IN, "GPIO7 X1-13"}, */
+ {APALIS_GPIO8, GPIOF_IN, "GPIO8 X1-15, FAN"},
+ {LVDS_MODE, GPIOF_IN, "LVDS: Single/Dual Ch"},
+ {LVDS_6B_8B_N, GPIOF_IN, "LVDS: 18/24 Bit Mode"},
+ {LVDS_OE, GPIOF_IN, "LVDS: Output Enable"},
+ {LVDS_PDWN_N, GPIOF_IN, "LVDS: Power Down"},
+ {LVDS_R_F_N, GPIOF_IN, "LVDS: Clock Polarity"},
+ {LVDS_MAP, GPIOF_IN, "LVDS: Colour Mapping"},
+ {LVDS_RS, GPIOF_IN, "LVDS: Swing Mode"},
+ {LVDS_DDR_N, GPIOF_IN, "LVDS: DDRclk Disable"},
+};
+
+static void apalis_t30_gpio_init(void)
+{
+ int i = 0;
+ int length = sizeof(apalis_t30_gpios) / sizeof(struct gpio);
+ int err = 0;
+
+ for (i = 0; i < length; i++) {
+ err = gpio_request_one(apalis_t30_gpios[i].gpio,
+ apalis_t30_gpios[i].flags,
+ apalis_t30_gpios[i].label);
+
+ if (err) {
+ pr_warning("gpio_request(%s) failed, err = %d",
+ apalis_t30_gpios[i].label, err);
+ } else {
+ gpio_export(apalis_t30_gpios[i].gpio, true);
+ }
+ }
+}
+
+
+/*
+ * Fusion touch screen GPIOs (using Toradex display/touch adapater)
+ * Apalis GPIO 5, MXM-11, Ixora X27-17, pen down interrupt
+ * Apalis GPIO 6, MXM-13, Ixora X27-18, reset
+ * gpio_request muxes the GPIO function automatically, we only have to make
+ * sure input/output muxing is done and the GPIO is freed here.
+ */
+static int pinmux_fusion_pins(void);
+
+static struct fusion_f0710a_init_data apalis_fusion_pdata = {
+ .pinmux_fusion_pins = &pinmux_fusion_pins,
+ .gpio_int = APALIS_GPIO5, /* MXM-11, Pen down interrupt */
+ .gpio_reset = APALIS_GPIO6, /* MXM-13, Reset interrupt */
+};
+
+static int pinmux_fusion_pins(void)
+{
+ gpio_free(apalis_fusion_pdata.gpio_int);
+ gpio_free(apalis_fusion_pdata.gpio_reset);
+ apalis_fusion_pdata.pinmux_fusion_pins = NULL;
+ return 0;
+}
+
+/* I2C */
+
+/* Make sure that the pinmuxing enable the 'open drain' feature for pins used
+ for I2C */
+
+/* GEN1_I2C: I2C1_SDA/SCL on MXM3 pin 209/211 (e.g. RTC on carrier board) */
+static struct i2c_board_info apalis_t30_i2c_bus1_board_info[] __initdata = {
+ {
+ /* M41T0M6 real time clock on Iris carrier board */
+ I2C_BOARD_INFO("rtc-ds1307", 0x68),
+ .type = "m41t00",
+ },
+ {
+ /* TouchRevolution Fusion 7 and 10 multi-touch controller */
+ I2C_BOARD_INFO("fusion_F0710A", 0x10),
+ .platform_data = &apalis_fusion_pdata,
+ },
+};
+
+static struct tegra_i2c_platform_data apalis_t30_i2c1_platform_data = {
+ .adapter_nr = 0,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {400000, 0},
+ .bus_count = 1,
+ .scl_gpio = {I2C1_SCL, 0},
+ .sda_gpio = {I2C1_SDA, 0},
+ .slave_addr = 0x00FC,
+};
+
+/* GEN2_I2C: unused */
+
+/* DDC: I2C2_SDA/SCL on MXM3 pin 205/207 (e.g. display EDID) */
+static struct tegra_i2c_platform_data apalis_t30_i2c4_platform_data = {
+ .adapter_nr = 3,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {10000, 10000},
+ .bus_count = 1,
+ .scl_gpio = {I2C2_SCL, 0},
+ .sda_gpio = {I2C2_SDA, 0},
+ .slave_addr = 0x00FC,
+};
+
+/* CAM_I2C: I2C3_SDA/SCL on MXM3 pin 201/203 (e.g. camera sensor on carrier
+ board) */
+static struct tegra_i2c_platform_data apalis_t30_i2c3_platform_data = {
+ .adapter_nr = 2,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {400000, 0},
+ .bus_count = 1,
+ .scl_gpio = {I2C3_SCL, 0},
+ .sda_gpio = {I2C3_SDA, 0},
+ .slave_addr = 0x00FC,
+};
+
+/* PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and touch screen
+ controller */
+
+/* STMPE811 touch screen controller */
+static struct stmpe_ts_platform_data stmpe811_ts_data = {
+ .adc_freq = 1, /* 3.25 MHz ADC clock speed */
+ .ave_ctrl = 3, /* 8 sample average control */
+ .fraction_z = 7, /* 7 length fractional part in z */
+ .i_drive = 1, /* 50 mA typical 80 mA max touchscreen
+ drivers current limit value */
+ .mod_12b = 1, /* 12-bit ADC */
+ .ref_sel = 0, /* internal ADC reference */
+ .sample_time = 4, /* ADC converstion time: 80 clocks */
+ .settling = 3, /* 1 ms panel driver settling time */
+ .touch_det_delay = 5, /* 5 ms touch detect interrupt delay */
+};
+
+/* STMPE811 ADC controller */
+static struct stmpe_adc_platform_data stmpe811_adc_data = {
+ .sample_time = 4, /* ADC converstion time: 80 clocks */
+ .mod_12b = 1, /* 12-bit ADC */
+ .ref_sel = 0, /* internal ADC reference */
+ .adc_freq = 1, /* 3.25 MHz ADC clock speed */
+};
+
+static struct stmpe_platform_data stmpe811_data = {
+ .blocks = STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC,
+ .id = 1,
+ .irq_base = STMPE811_IRQ_BASE,
+ .irq_trigger = IRQF_TRIGGER_FALLING,
+ .ts = &stmpe811_ts_data,
+ .adc = &stmpe811_adc_data,
+};
+
+static void lm95245_probe_callback(struct device *dev);
+
+static struct lm95245_platform_data apalis_t30_lm95245_pdata = {
+ .enable_os_pin = true,
+ .probe_callback = lm95245_probe_callback,
+};
+
+static struct i2c_board_info apalis_t30_i2c_bus5_board_info[] __initdata = {
+ {
+ /* SGTL5000 audio codec */
+ I2C_BOARD_INFO("sgtl5000", 0x0a),
+ },
+ {
+ /* STMPE811 touch screen controller */
+ I2C_BOARD_INFO("stmpe", 0x41),
+ .flags = I2C_CLIENT_WAKE,
+ .platform_data = &stmpe811_data,
+ .type = "stmpe811",
+ },
+ {
+ /* LM95245 temperature sensor
+ Note: OVERT_N directly connected to PMIC PWRDN */
+ I2C_BOARD_INFO("lm95245", 0x4c),
+ .platform_data = &apalis_t30_lm95245_pdata,
+ },
+};
+
+static struct tegra_i2c_platform_data apalis_t30_i2c5_platform_data = {
+ .adapter_nr = 4,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {400000, 0},
+ .bus_count = 1,
+ .scl_gpio = {PWR_I2C_SCL, 0},
+ .sda_gpio = {PWR_I2C_SDA, 0},
+};
+
+static void __init apalis_t30_i2c_init(void)
+{
+ tegra_i2c_device1.dev.platform_data = &apalis_t30_i2c1_platform_data;
+ tegra_i2c_device3.dev.platform_data = &apalis_t30_i2c3_platform_data;
+ tegra_i2c_device4.dev.platform_data = &apalis_t30_i2c4_platform_data;
+ tegra_i2c_device5.dev.platform_data = &apalis_t30_i2c5_platform_data;
+
+ platform_device_register(&tegra_i2c_device1);
+ platform_device_register(&tegra_i2c_device3);
+ platform_device_register(&tegra_i2c_device4);
+ platform_device_register(&tegra_i2c_device5);
+
+ i2c_register_board_info(0, apalis_t30_i2c_bus1_board_info,
+ ARRAY_SIZE(apalis_t30_i2c_bus1_board_info));
+
+ /* enable touch interrupt GPIO */
+ gpio_request(TOUCH_PEN_INT, "TOUCH_PEN_INT");
+ gpio_direction_input(TOUCH_PEN_INT);
+
+ apalis_t30_i2c_bus5_board_info[1].irq = gpio_to_irq(TOUCH_PEN_INT);
+ i2c_register_board_info(4, apalis_t30_i2c_bus5_board_info,
+ ARRAY_SIZE(apalis_t30_i2c_bus5_board_info));
+}
+
+/* IrDA */
+
+//TODO
+
+/* Keys
+ * Note: active-low means pull-ups required on carrier board resp. via
+ * pin-muxing
+ * Note2: power-key active-high due to EvalBoard v3.1a having 100 K pull-down
+ * on SODIMM pin 45
+ * Note3: menu-key active-high due to strong pull-down on multiplexed
+ * ACC1_DETECT
+ * Note4: Wake keys need to be supported by hardware, see wakeups-t3.h
+ */
+
+#ifdef CONFIG_KEYBOARD_GPIO
+#define GPIO_KEY(_id, _gpio, _lowactive, _iswake) \
+ { \
+ .code = _id, \
+ .gpio = TEGRA_GPIO_##_gpio, \
+ .active_low = _lowactive, \
+ .desc = #_id, \
+ .type = EV_KEY, \
+ .wakeup = _iswake, \
+ .debounce_interval = 10, \
+ }
+
+static struct gpio_keys_button apalis_t30_keys[] = {
+ GPIO_KEY(KEY_POWER, PV1, 0, 1), /* SODIMM pin 45, Iris X16-20/EvalBoard X3 B24 */
+};
+
+#define PMC_WAKE_STATUS 0x14
+
+static int apalis_t30_wakeup_key(void)
+{
+ unsigned long status =
+ readl(IO_ADDRESS(TEGRA_PMC_BASE) + PMC_WAKE_STATUS);
+
+ return (status & (1 << TEGRA_WAKE_GPIO_PV1)) ?
+ KEY_POWER : KEY_RESERVED;
+}
+
+static struct gpio_keys_platform_data apalis_t30_keys_platform_data = {
+ .buttons = apalis_t30_keys,
+ .nbuttons = ARRAY_SIZE(apalis_t30_keys),
+ .wakeup_key = apalis_t30_wakeup_key,
+};
+
+static struct platform_device apalis_t30_keys_device = {
+ .name = "gpio-keys",
+ .id = 0,
+ .dev = {
+ .platform_data = &apalis_t30_keys_platform_data,
+ },
+};
+#endif /* CONFIG_KEYBOARD_GPIO */
+
+/* MMC/SD */
+
+static struct tegra_sdhci_platform_data apalis_t30_emmc_platform_data = {
+ .cd_gpio = -1,
+ .ddr_clk_limit = 52000000,
+ .is_8bit = 1,
+ .mmc_data = {
+ .built_in = 1,
+ },
+ .power_gpio = -1,
+ .tap_delay = 0x0f,
+ .wp_gpio = -1,
+};
+
+static struct tegra_sdhci_platform_data apalis_t30_mmccard_platform_data = {
+ .cd_gpio = MMC1_CD_N,
+ .ddr_clk_limit = 52000000,
+ .is_8bit = 1,
+ .power_gpio = -1,
+ .tap_delay = 0x0f,
+ .wp_gpio = -1,
+};
+
+static struct tegra_sdhci_platform_data apalis_t30_sdcard_platform_data = {
+ .cd_gpio = SD1_CD_N,
+ .ddr_clk_limit = 52000000,
+ .is_8bit = 0,
+ .power_gpio = -1,
+ .tap_delay = 0x0f,
+ .wp_gpio = -1,
+};
+
+static void __init apalis_t30_sdhci_init(void)
+{
+ /* register eMMC first */
+ tegra_sdhci_device4.dev.platform_data =
+ &apalis_t30_emmc_platform_data;
+ platform_device_register(&tegra_sdhci_device4);
+
+ tegra_sdhci_device3.dev.platform_data =
+ &apalis_t30_mmccard_platform_data;
+ platform_device_register(&tegra_sdhci_device3);
+
+ tegra_sdhci_device1.dev.platform_data =
+ &apalis_t30_sdcard_platform_data;
+ platform_device_register(&tegra_sdhci_device1);
+}
+
+/* PCIe */
+
+/* The Apalis evaluation board needs to set the link speed to 2.5 GT/s (GEN1).
+ The default link speed setting is 5 GT/s (GEN2). 0x98 is the Link Control 2
+ PCIe Capability Register of the PEX8605 PCIe switch. The switch supports
+ link speed auto negotiation, but falsely sets the link speed to 5 GT/s. */
+static void __devinit quirk_apalis_plx_gen1(struct pci_dev *dev)
+{
+ pci_write_config_dword(dev, 0x98, 0x01);
+ mdelay(50);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8605, quirk_apalis_plx_gen1);
+
+static struct tegra_pci_platform_data apalis_t30_pci_platform_data = {
+ .port_status[0] = 1,
+ .port_status[1] = 1,
+ .port_status[2] = 1,
+ .use_dock_detect = 0,
+ .gpio = 0,
+};
+
+static void apalis_t30_pci_init(void)
+{
+ /* Reset PLX PEX 8605 PCIe Switch plus PCIe devices on Apalis Evaluation
+ Board */
+ gpio_request(PEX_PERST_N, "PEX_PERST_N");
+ gpio_request(RESET_MOCI_N, "RESET_MOCI_N");
+ gpio_direction_output(PEX_PERST_N, 0);
+ gpio_direction_output(RESET_MOCI_N, 0);
+ /* Must be asserted for 100 ms after power and clocks are stable */
+ msleep(100);
+ gpio_set_value(PEX_PERST_N, 1);
+ /* Err_5: PEX_REFCLK_OUTpx/nx Clock Outputs is not Guaranteed Until
+ 900 us After PEX_PERST# De-assertion */
+ msleep(1);
+ gpio_set_value(RESET_MOCI_N, 1);
+
+ tegra_pci_device.dev.platform_data = &apalis_t30_pci_platform_data;
+ platform_device_register(&tegra_pci_device);
+}
+
+/* PWM LEDs */
+static struct led_pwm tegra_leds_pwm[] = {
+ {
+ .name = "PWM3",
+ .pwm_id = 1,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+ {
+ .name = "PWM2",
+ .pwm_id = 2,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+ {
+ .name = "PWM1",
+ .pwm_id = 3,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+};
+
+static struct led_pwm_platform_data tegra_leds_pwm_data = {
+ .num_leds = ARRAY_SIZE(tegra_leds_pwm),
+ .leds = tegra_leds_pwm,
+};
+
+static struct platform_device tegra_led_pwm_device = {
+ .name = "leds_pwm",
+ .id = -1,
+ .dev = {
+ .platform_data = &tegra_leds_pwm_data,
+ },
+};
+
+/* RTC */
+
+#ifdef CONFIG_RTC_DRV_TEGRA
+static struct resource tegra_rtc_resources[] = {
+ [0] = {
+ .start = TEGRA_RTC_BASE,
+ .end = TEGRA_RTC_BASE + TEGRA_RTC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = INT_RTC,
+ .end = INT_RTC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tegra_rtc_device = {
+ .name = "tegra_rtc",
+ .id = -1,
+ .resource = tegra_rtc_resources,
+ .num_resources = ARRAY_SIZE(tegra_rtc_resources),
+};
+#endif /* CONFIG_RTC_DRV_TEGRA */
+
+/* SATA */
+
+#ifdef CONFIG_SATA_AHCI_TEGRA
+static struct gpio_led apalis_gpio_leds[] = {
+ [0] = {
+ .name = "SATA1_ACT_N",
+ .default_trigger = "ide-disk",
+ .gpio = SATA1_ACT_N,
+ .active_low = 1,
+ .retain_state_suspended = 0,
+ },
+};
+
+static struct gpio_led_platform_data apalis_gpio_led_data = {
+ .num_leds = ARRAY_SIZE(apalis_gpio_leds),
+ .leds = apalis_gpio_leds,
+};
+
+static struct platform_device apalis_led_gpio_device = {
+ .name = "leds-gpio",
+ .dev = {
+ .platform_data = &apalis_gpio_led_data,
+ },
+};
+
+static void apalis_t30_sata_init(void)
+{
+ platform_device_register(&tegra_sata_device);
+ platform_device_register(&apalis_led_gpio_device);
+}
+#else
+static void apalis_t30_sata_init(void) { }
+#endif
+
+/* SPI */
+
+#if defined(CONFIG_SPI_TEGRA) && defined(CONFIG_SPI_SPIDEV)
+static struct spi_board_info tegra_spi_devices[] __initdata = {
+ {
+ .bus_num = 0, /* SPI1: Apalis SPI1 */
+ .chip_select = 0,
+ .irq = 0,
+ .max_speed_hz = 50000000,
+ .modalias = "spidev",
+ .mode = SPI_MODE_0,
+ .platform_data = NULL,
+ },
+ {
+ .bus_num = 4, /* SPI5: Apalis SPI2 */
+ .chip_select = 2,
+ .irq = 0,
+ .max_speed_hz = 50000000,
+ .modalias = "spidev",
+ .mode = SPI_MODE_0,
+ .platform_data = NULL,
+ },
+};
+
+static void __init apalis_t30_register_spidev(void)
+{
+ spi_register_board_info(tegra_spi_devices,
+ ARRAY_SIZE(tegra_spi_devices));
+}
+#else /* CONFIG_SPI_TEGRA && CONFIG_SPI_SPIDEV */
+#define apalis_t30_register_spidev() do {} while (0)
+#endif /* CONFIG_SPI_TEGRA && CONFIG_SPI_SPIDEV */
+
+static struct platform_device *apalis_t30_spi_devices[] __initdata = {
+ &tegra_spi_device1,
+ &tegra_spi_device2,
+ &tegra_spi_device4,
+ &tegra_spi_device5,
+};
+
+static struct spi_clk_parent spi_parent_clk[] = {
+ [0] = {.name = "pll_p"},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
+ [1] = {.name = "pll_m"},
+ [2] = {.name = "clk_m"},
+#else /* !CONFIG_TEGRA_PLLM_RESTRICTED */
+ [1] = {.name = "clk_m"},
+#endif /* !CONFIG_TEGRA_PLLM_RESTRICTED */
+};
+
+static struct tegra_spi_platform_data apalis_t30_spi_pdata = {
+ .is_dma_based = true,
+ .max_dma_buffer = 16 * 1024,
+ .is_clkon_always = false,
+ .max_rate = 100000000,
+};
+
+static void __init apalis_t30_spi_init(void)
+{
+ int i;
+ struct clk *c;
+
+ for (i = 0; i < ARRAY_SIZE(spi_parent_clk); ++i) {
+ c = tegra_get_clock_by_name(spi_parent_clk[i].name);
+ if (IS_ERR_OR_NULL(c)) {
+ pr_err("Not able to get the clock for %s\n",
+ spi_parent_clk[i].name);
+ continue;
+ }
+ spi_parent_clk[i].parent_clk = c;
+ spi_parent_clk[i].fixed_clk_rate = clk_get_rate(c);
+ }
+ apalis_t30_spi_pdata.parent_clk_list = spi_parent_clk;
+ apalis_t30_spi_pdata.parent_clk_count = ARRAY_SIZE(spi_parent_clk);
+ tegra_spi_device1.dev.platform_data = &apalis_t30_spi_pdata;
+ platform_add_devices(apalis_t30_spi_devices,
+ ARRAY_SIZE(apalis_t30_spi_devices));
+}
+
+/* Thermal throttling */
+
+static void *apalis_t30_alert_data;
+static void (*apalis_t30_alert_func)(void *);
+static int apalis_t30_low_edge = 0;
+static int apalis_t30_low_hysteresis = 3000;
+static int apalis_t30_low_limit = 0;
+static struct device *lm95245_device = NULL;
+static int thermd_alert_irq_disabled = 0;
+struct work_struct thermd_alert_work;
+struct workqueue_struct *thermd_alert_workqueue;
+
+static struct balanced_throttle throttle_list[] = {
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ {
+ .id = BALANCED_THROTTLE_ID_TJ,
+ .throt_tab_size = 10,
+ .throt_tab = {
+ { 0, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 760000, 1000 },
+ { 760000, 1050 },
+ {1000000, 1050 },
+ {1000000, 1100 },
+ },
+ },
+#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ {
+ .id = BALANCED_THROTTLE_ID_SKIN,
+ .throt_tab_size = 6,
+ .throt_tab = {
+ { 640000, 1200 },
+ { 640000, 1200 },
+ { 760000, 1200 },
+ { 760000, 1200 },
+ {1000000, 1200 },
+ {1000000, 1200 },
+ },
+ },
+#endif /* CONFIG_TEGRA_SKIN_THROTTLE */
+};
+
+/* All units are in millicelsius */
+static struct tegra_thermal_data thermal_data = {
+ .shutdown_device_id = THERMAL_DEVICE_ID_NCT_EXT,
+ .temp_shutdown = 115000,
+
+#if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE)
+ .throttle_edp_device_id = THERMAL_DEVICE_ID_NCT_EXT,
+#endif
+#ifdef CONFIG_TEGRA_EDP_LIMITS
+ .edp_offset = TDIODE_OFFSET, /* edp based on tdiode */
+ .hysteresis_edp = 3000,
+#endif
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ .temp_throttle = 85000,
+ .tc1 = 0,
+ .tc2 = 1,
+ .passive_delay = 2000,
+#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ .skin_device_id = THERMAL_DEVICE_ID_SKIN,
+ .temp_throttle_skin = 43000,
+ .tc1_skin = 0,
+ .tc2_skin = 1,
+ .passive_delay_skin = 5000,
+
+ .skin_temp_offset = 9793,
+ .skin_period = 1100,
+ .skin_devs_size = 2,
+ .skin_devs = {
+ {
+ THERMAL_DEVICE_ID_NCT_EXT,
+ {
+ 2, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 0,
+ 1, 1, 0, 0,
+ 0, 0, -1, -7
+ }
+ },
+ {
+ THERMAL_DEVICE_ID_NCT_INT,
+ {
+ -11, -7, -5, -3,
+ -3, -2, -1, 0,
+ 0, 0, 1, 1,
+ 1, 2, 2, 3,
+ 4, 6, 11, 18
+ }
+ },
+ },
+#endif /* CONFIG_TEGRA_SKIN_THROTTLE */
+};
+
+/* Over-temperature shutdown OS aka high limit GPIO pin interrupt handler */
+static irqreturn_t thermd_alert_irq(int irq, void *data)
+{
+ disable_irq_nosync(irq);
+ thermd_alert_irq_disabled = 1;
+ queue_work(thermd_alert_workqueue, &thermd_alert_work);
+
+ return IRQ_HANDLED;
+}
+
+/* Gets both entered by THERMD_ALERT GPIO interrupt as well as re-scheduled. */
+static void thermd_alert_work_func(struct work_struct *work)
+{
+ int temp = 0;
+
+ lm95245_get_remote_temp(lm95245_device, &temp);
+
+ /* This emulates NCT1008 low limit behaviour */
+ if (!apalis_t30_low_edge && temp <= apalis_t30_low_limit) {
+ apalis_t30_alert_func(apalis_t30_alert_data);
+ apalis_t30_low_edge = 1;
+ } else if (apalis_t30_low_edge && temp > apalis_t30_low_limit +
+ apalis_t30_low_hysteresis) {
+ apalis_t30_low_edge = 0;
+ }
+
+ /* Avoid unbalanced enable for IRQ 367 */
+ if (thermd_alert_irq_disabled) {
+ apalis_t30_alert_func(apalis_t30_alert_data);
+ thermd_alert_irq_disabled = 0;
+ enable_irq(gpio_to_irq(THERMD_ALERT_N));
+ }
+
+ /* Keep re-scheduling */
+ msleep(2000);
+ queue_work(thermd_alert_workqueue, &thermd_alert_work);
+}
+
+static int lm95245_get_temp(void *_data, long *temp)
+{
+ struct device *lm95245_device = _data;
+ int lm95245_temp = 0;
+ lm95245_get_remote_temp(lm95245_device, &lm95245_temp);
+ *temp = lm95245_temp;
+ return 0;
+}
+
+static int lm95245_get_temp_low(void *_data, long *temp)
+{
+ *temp = 0;
+ return 0;
+}
+
+/* Our temperature sensor only allows triggering an interrupt on over-
+ temperature shutdown aka the high limit we therefore need to setup a
+ workqueue to catch leaving the low limit. */
+static int lm95245_set_limits(void *_data,
+ long lo_limit_milli,
+ long hi_limit_milli)
+{
+ struct device *lm95245_device = _data;
+ apalis_t30_low_limit = lo_limit_milli;
+ if (lm95245_device) lm95245_set_remote_os_limit(lm95245_device,
+ hi_limit_milli);
+ return 0;
+}
+
+static int lm95245_set_alert(void *_data,
+ void (*alert_func)(void *),
+ void *alert_data)
+{
+ lm95245_device = _data;
+ apalis_t30_alert_func = alert_func;
+ apalis_t30_alert_data = alert_data;
+ return 0;
+}
+
+static int lm95245_set_shutdown_temp(void *_data, long shutdown_temp)
+{
+ struct device *lm95245_device = _data;
+ if (lm95245_device) lm95245_set_remote_critical_limit(lm95245_device,
+ shutdown_temp);
+ return 0;
+}
+
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+/* Internal aka local board/case temp */
+static int lm95245_get_itemp(void *dev_data, long *temp)
+{
+ struct device *lm95245_device = dev_data;
+ int lm95245_temp = 0;
+ lm95245_get_local_temp(lm95245_device, &lm95245_temp);
+ *temp = lm95245_temp;
+ return 0;
+}
+#endif /* CONFIG_TEGRA_SKIN_THROTTLE */
+
+static void lm95245_probe_callback(struct device *dev)
+{
+ struct tegra_thermal_device *lm95245_remote;
+
+ lm95245_remote = kzalloc(sizeof(struct tegra_thermal_device),
+ GFP_KERNEL);
+ if (!lm95245_remote) {
+ pr_err("unable to allocate thermal device\n");
+ return;
+ }
+
+ lm95245_remote->name = "lm95245_remote";
+ lm95245_remote->id = THERMAL_DEVICE_ID_NCT_EXT;
+ lm95245_remote->data = dev;
+ lm95245_remote->offset = TDIODE_OFFSET;
+ lm95245_remote->get_temp = lm95245_get_temp;
+ lm95245_remote->get_temp_low = lm95245_get_temp_low;
+ lm95245_remote->set_limits = lm95245_set_limits;
+ lm95245_remote->set_alert = lm95245_set_alert;
+ lm95245_remote->set_shutdown_temp = lm95245_set_shutdown_temp;
+
+ tegra_thermal_device_register(lm95245_remote);
+
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ {
+ struct tegra_thermal_device *lm95245_local;
+ lm95245_local = kzalloc(sizeof(struct tegra_thermal_device),
+ GFP_KERNEL);
+ if (!lm95245_local) {
+ kfree(lm95245_local);
+ pr_err("unable to allocate thermal device\n");
+ return;
+ }
+
+ lm95245_local->name = "lm95245_local";
+ lm95245_local->id = THERMAL_DEVICE_ID_NCT_INT;
+ lm95245_local->data = dev;
+ lm95245_local->get_temp = lm95245_get_itemp;
+
+ tegra_thermal_device_register(lm95245_local);
+ }
+#endif /* CONFIG_TEGRA_SKIN_THROTTLE */
+
+ if (request_irq(gpio_to_irq(THERMD_ALERT_N), thermd_alert_irq,
+ IRQF_TRIGGER_LOW, "THERMD_ALERT_N", NULL))
+ pr_err("%s: unable to register THERMD_ALERT_N interrupt\n",
+ __func__);
+
+ //initalize the local temp limit
+ if(dev)
+ lm95245_set_local_shared_os__critical_limit(dev, TCRIT_LOCAL);
+}
+
+static void apalis_t30_thermd_alert_init(void)
+{
+ gpio_request(THERMD_ALERT_N, "THERMD_ALERT_N");
+ gpio_direction_input(THERMD_ALERT_N);
+
+ thermd_alert_workqueue = create_singlethread_workqueue("THERMD_ALERT_N"
+ );
+
+ INIT_WORK(&thermd_alert_work, thermd_alert_work_func);
+}
+
+/* UART */
+
+static struct platform_device *apalis_t30_uart_devices[] __initdata = {
+ &tegra_uarta_device, /* Apalis UART1 */
+ &tegra_uartd_device, /* Apalis UART2 */
+ &tegra_uartb_device, /* Apalis UART3 */
+ &tegra_uartc_device, /* Apalis UART4 */
+};
+
+static struct uart_clk_parent uart_parent_clk[] = {
+ [0] = {.name = "clk_m"},
+ [1] = {.name = "pll_p"},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
+ [2] = {.name = "pll_m"},
+#endif
+};
+
+static struct tegra_uart_platform_data apalis_t30_uart_pdata;
+
+static void __init uart_debug_init(void)
+{
+ int debug_port_id;
+
+ debug_port_id = get_tegra_uart_debug_port_id();
+ if (debug_port_id < 0) {
+ debug_port_id = 0;
+ }
+
+ switch (debug_port_id) {
+ case 0:
+ /* UARTA is the debug port. */
+ pr_info("Selecting UARTA as the debug console\n");
+ apalis_t30_uart_devices[0] = &debug_uarta_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uarta");
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uarta_device.dev.platform_data))->mapbase;
+ break;
+
+ case 1:
+ /* UARTB is the debug port. */
+ pr_info("Selecting UARTB as the debug console\n");
+ apalis_t30_uart_devices[2] = &debug_uartb_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uartb");
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uartb_device.dev.platform_data))->mapbase;
+ break;
+
+ case 2:
+ /* UARTC is the debug port. */
+ pr_info("Selecting UARTC as the debug console\n");
+ apalis_t30_uart_devices[3] = &debug_uartc_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uartc");
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uartb_device.dev.platform_data))->mapbase;
+ break;
+
+ case 3:
+ /* UARTD is the debug port. */
+ pr_info("Selecting UARTD as the debug console\n");
+ apalis_t30_uart_devices[1] = &debug_uartd_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uartd");
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uartd_device.dev.platform_data))->mapbase;
+ break;
+
+ default:
+ pr_info("The debug console id %d is invalid, Assuming UARTA",
+ debug_port_id);
+ apalis_t30_uart_devices[0] = &debug_uarta_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uarta");
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uarta_device.dev.platform_data))->mapbase;
+ break;
+ }
+ return;
+}
+
+static void __init apalis_t30_uart_init(void)
+{
+ struct clk *c;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(uart_parent_clk); ++i) {
+ c = tegra_get_clock_by_name(uart_parent_clk[i].name);
+ if (IS_ERR_OR_NULL(c)) {
+ pr_err("Not able to get the clock for %s\n",
+ uart_parent_clk[i].name);
+ continue;
+ }
+ uart_parent_clk[i].parent_clk = c;
+ uart_parent_clk[i].fixed_clk_rate = clk_get_rate(c);
+ }
+ apalis_t30_uart_pdata.parent_clk_list = uart_parent_clk;
+ apalis_t30_uart_pdata.parent_clk_count = ARRAY_SIZE(uart_parent_clk);
+ tegra_uarta_device.dev.platform_data = &apalis_t30_uart_pdata;
+ tegra_uartb_device.dev.platform_data = &apalis_t30_uart_pdata;
+ tegra_uartc_device.dev.platform_data = &apalis_t30_uart_pdata;
+ tegra_uartd_device.dev.platform_data = &apalis_t30_uart_pdata;
+
+ /* Register low speed only if it is selected */
+ if (!is_tegra_debug_uartport_hs()) {
+ uart_debug_init();
+ /* Clock enable for the debug channel */
+ if (!IS_ERR_OR_NULL(debug_uart_clk)) {
+ pr_info("The debug console clock name is %s\n",
+ debug_uart_clk->name);
+ c = tegra_get_clock_by_name("pll_p");
+ if (IS_ERR_OR_NULL(c))
+ pr_err("Not getting the parent clock pll_p\n");
+ else
+ clk_set_parent(debug_uart_clk, c);
+
+ clk_enable(debug_uart_clk);
+ clk_set_rate(debug_uart_clk, clk_get_rate(c));
+ } else {
+ pr_err("Not getting the clock %s for debug console\n",
+ debug_uart_clk->name);
+ }
+ }
+
+ platform_add_devices(apalis_t30_uart_devices,
+ ARRAY_SIZE(apalis_t30_uart_devices));
+}
+
+/* USB */
+
+//TODO: overcurrent
+
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .has_hostpc = true,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = true,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 8,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+ .u_data.dev = {
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
+ .vbus_gpio = -1,
+ .vbus_pmu_irq = 0,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .has_hostpc = true,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = true,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 15,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+ .u_data.host = {
+ .hot_plug = true,
+ .power_off_on_suspend = false,
+ .remote_wakeup_supported = true,
+ .vbus_gpio = USBO1_EN,
+ .vbus_gpio_inverted = 0,
+ .vbus_reg = NULL,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = {
+ .has_hostpc = true,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = false,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 15,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+ .u_data.host = {
+ .hot_plug = true,
+ .power_off_on_suspend = false,
+ .remote_wakeup_supported = true,
+ .vbus_gpio = USBH_EN,
+ .vbus_gpio_inverted = 0,
+ .vbus_reg = NULL,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
+ .has_hostpc = true,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = false,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 8,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+ .u_data.host = {
+ .hot_plug = true,
+ .power_off_on_suspend = false,
+ .remote_wakeup_supported = true,
+ /* Uses same USBH_EN as EHCI2 */
+ .vbus_gpio = -1,
+ .vbus_gpio_inverted = 0,
+ .vbus_reg = NULL,
+ },
+};
+
+static struct tegra_usb_otg_data tegra_otg_pdata = {
+ .ehci_device = &tegra_ehci1_device,
+ .ehci_pdata = &tegra_ehci1_utmi_pdata,
+};
+
+static void apalis_t30_usb_init(void)
+{
+ /* OTG should be the first to be registered
+ EHCI instance 0: USB1_DP/N -> USBO1_DP/N */
+ tegra_otg_device.dev.platform_data = &tegra_otg_pdata;
+ platform_device_register(&tegra_otg_device);
+
+ /* setup the udc platform data */
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
+ platform_device_register(&tegra_udc_device);
+
+ /* EHCI instance 1: USB2_DP/N -> USBH2_DP/N */
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata;
+ platform_device_register(&tegra_ehci2_device);
+
+ /* EHCI instance 2: USB3_DP/N -> USBH3_DP/N */
+ tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata;
+ platform_device_register(&tegra_ehci3_device);
+}
+
+/* W1, aka OWR, aka OneWire */
+
+#ifdef CONFIG_W1_MASTER_TEGRA
+struct tegra_w1_timings apalis_t30_w1_timings = {
+ .tsu = 1,
+ .trelease = 0xf,
+ .trdv = 0xf,
+ .tlow0 = 0x3c,
+ .tlow1 = 1,
+ .tslot = 0x77,
+
+ .tpdl = 0x78,
+ .tpdh = 0x1e,
+ .trstl = 0x1df,
+ .trsth = 0x1df,
+ .rdsclk = 0x7,
+ .psclk = 0x50,
+};
+
+struct tegra_w1_platform_data apalis_t30_w1_platform_data = {
+ .clk_id = "tegra_w1",
+ .timings = &apalis_t30_w1_timings,
+};
+#endif /* CONFIG_W1_MASTER_TEGRA */
+
+static struct platform_device *apalis_t30_devices[] __initdata = {
+ &tegra_pmu_device,
+#if defined(CONFIG_RTC_DRV_TEGRA)
+ &tegra_rtc_device,
+#endif
+#if defined(CONFIG_TEGRA_IOVMM_SMMU) || defined(CONFIG_TEGRA_IOMMU_SMMU)
+ &tegra_smmu_device,
+#endif
+#ifdef CONFIG_KEYBOARD_GPIO
+ &apalis_t30_keys_device,
+#endif
+ &tegra_wdt0_device,
+ &tegra_wdt1_device,
+ &tegra_wdt2_device,
+#if defined(CONFIG_TEGRA_AVP)
+ &tegra_avp_device,
+#endif
+#ifdef CONFIG_TEGRA_CAMERA
+ &tegra_camera,
+#endif
+#if defined(CONFIG_CRYPTO_DEV_TEGRA_SE)
+ &tegra_se_device,
+#endif
+#if defined(CONFIG_CRYPTO_DEV_TEGRA_AES)
+ &tegra_aes_device,
+#endif
+ &tegra_ahub_device,
+ &tegra_dam_device0,
+ &tegra_dam_device1,
+ &tegra_dam_device2,
+ &tegra_i2s_device2,
+ &tegra_spdif_device,
+ &spdif_dit_device,
+ &tegra_pcm_device,
+ &apalis_t30_audio_sgtl5000_device,
+ &tegra_hda_device,
+ &tegra_cec_device,
+#ifdef CONFIG_KEYBOARD_GPIO
+// &apalis_t30_keys_device,
+#endif
+ &tegra_led_pwm_device,
+ &tegra_pwfm1_device,
+ &tegra_pwfm2_device,
+ &tegra_pwfm3_device,
+#ifdef CONFIG_W1_MASTER_TEGRA
+ &tegra_w1_device,
+#endif
+};
+
+static void __init apalis_t30_init(void)
+{
+ tegra_thermal_init(&thermal_data,
+ throttle_list,
+ ARRAY_SIZE(throttle_list));
+ tegra_clk_init_from_table(apalis_t30_clk_init_table);
+ apalis_t30_pinmux_init();
+ apalis_t30_thermd_alert_init();
+ apalis_t30_i2c_init();
+ apalis_t30_spi_init();
+ apalis_t30_usb_init();
+#ifdef CONFIG_TEGRA_EDP_LIMITS
+ apalis_t30_edp_init();
+#endif
+ apalis_t30_uart_init();
+#ifdef CONFIG_W1_MASTER_TEGRA
+ tegra_w1_device.dev.platform_data = &apalis_t30_w1_platform_data;
+#endif
+ platform_add_devices(apalis_t30_devices, ARRAY_SIZE(apalis_t30_devices)
+ );
+ tegra_ram_console_debug_init();
+ tegra_io_dpd_init();
+ apalis_t30_sdhci_init();
+ apalis_t30_regulator_init();
+ apalis_t30_suspend_init();
+ apalis_t30_panel_init();
+// apalis_t30_sensors_init();
+ apalis_t30_sata_init();
+ apalis_t30_emc_init();
+ apalis_t30_register_spidev();
+
+#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE)
+ t30_get_tegra_vi01_device()->dev.platform_data = &tegra_camera_platform_data;
+#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE)
+ platform_device_register(&soc_camera_max9526);
+#endif
+#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE)
+ platform_device_register(&soc_camera_adv7180);
+#endif
+#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */
+
+ tegra_release_bootloader_fb();
+ apalis_t30_pci_init();
+#ifdef CONFIG_TEGRA_WDT_RECOVERY
+ tegra_wdt_recovery_init();
+#endif
+ tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1);
+ apalis_t30_mcp2515_can_init();
+ apalis_t30_gpio_init();
+}
+
+static void __init apalis_t30_reserve(void)
+{
+#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM)
+ /* Support 1920X1080 32bpp,double buffered on HDMI*/
+ tegra_reserve(0, SZ_8M + SZ_1M, SZ_16M);
+#else
+ tegra_reserve(SZ_128M, SZ_8M, SZ_8M);
+#endif
+ tegra_ram_console_debug_reserve(SZ_1M);
+}
+
+static const char *apalis_t30_dt_board_compat[] = {
+ "toradex,apalis_t30",
+ NULL
+};
+
+MACHINE_START(APALIS_T30, "Toradex Apalis T30")
+ .boot_params = 0x80000100,
+ .dt_compat = apalis_t30_dt_board_compat,
+ .init_early = tegra_init_early,
+ .init_irq = tegra_init_irq,
+ .init_machine = apalis_t30_init,
+ .map_io = tegra_map_common_io,
+ .reserve = apalis_t30_reserve,
+ .timer = &tegra_timer,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/board-apalis_t30.h b/arch/arm/mach-tegra/board-apalis_t30.h
new file mode 100644
index 000000000000..9fde9ef1d89e
--- /dev/null
+++ b/arch/arm/mach-tegra/board-apalis_t30.h
@@ -0,0 +1,140 @@
+/*
+ * arch/arm/mach-tegra/board-apalis_t30.h
+ *
+ * Copyright (c) 2013 Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 _MACH_TEGRA_BOARD_APALIS_T30_H
+#define _MACH_TEGRA_BOARD_APALIS_T30_H
+
+#include <linux/mfd/tps6591x.h>
+
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+
+/* GPIO */
+
+#define APALIS_GPIO1 TEGRA_GPIO_PS2
+#define APALIS_GPIO2 TEGRA_GPIO_PS3
+#define APALIS_GPIO3 TEGRA_GPIO_PS4
+#define APALIS_GPIO4 TEGRA_GPIO_PS5
+#define APALIS_GPIO5 TEGRA_GPIO_PS6
+#define APALIS_GPIO6 TEGRA_GPIO_PQ0
+#define APALIS_GPIO7 TEGRA_GPIO_PS7
+#define APALIS_GPIO8 TEGRA_GPIO_PQ1
+
+#define BKL1_ON TEGRA_GPIO_PV2
+#define BKL1_PWM_EN_N TEGRA_GPIO_PA1
+
+#define CAN1_INT TEGRA_GPIO_PW2
+#define CAN2_INT TEGRA_GPIO_PW3
+
+#define FAN_EN APALIS_GPIO8
+
+#define HDMI1_HPD TEGRA_GPIO_PN7
+
+#define I2C1_SCL TEGRA_GPIO_PC4
+#define I2C1_SDA TEGRA_GPIO_PC5
+
+#define I2C2_SCL TEGRA_GPIO_PV4
+#define I2C2_SDA TEGRA_GPIO_PV5
+
+#define I2C3_SCL TEGRA_GPIO_PBB1
+#define I2C3_SDA TEGRA_GPIO_PBB2
+
+#define LAN_SMB_ALERT_N TEGRA_GPIO_PZ5
+
+#define LVDS_MODE TEGRA_GPIO_PBB0
+#define LVDS_6B_8B_N TEGRA_GPIO_PBB3
+#define LVDS_OE TEGRA_GPIO_PBB4
+#define LVDS_PDWN_N TEGRA_GPIO_PBB5
+#define LVDS_R_F_N TEGRA_GPIO_PBB6
+#define LVDS_MAP TEGRA_GPIO_PBB7
+#define LVDS_RS TEGRA_GPIO_PCC1
+#define LVDS_DDR_N TEGRA_GPIO_PCC2
+
+#define MMC1_CD_N TEGRA_GPIO_PV3
+
+#define PEX_PERST_N APALIS_GPIO7
+
+#define PWR_I2C_SCL TEGRA_GPIO_PZ6
+#define PWR_I2C_SDA TEGRA_GPIO_PZ7
+
+#define RESET_MOCI_N TEGRA_GPIO_PI4
+
+#define SATA1_ACT_N TEGRA_GPIO_PDD0
+
+#define SD1_CD_N TEGRA_GPIO_PCC5
+
+#define THERMD_ALERT_N TEGRA_GPIO_PD2
+
+#define TOUCH_PEN_INT TEGRA_GPIO_PV0
+#define TOUCH_WIPER APALIS_GPIO6
+
+#define TS1 TEGRA_GPIO_PI1
+#define TS2 TEGRA_GPIO_PQ7
+#define TS3 TEGRA_GPIO_PQ5
+#define TS4 TEGRA_GPIO_PQ6
+#define TS5 TEGRA_GPIO_PS0
+#define TS6 TEGRA_GPIO_PS1
+
+#define USBH_EN TEGRA_GPIO_PDD1
+#define USBH_OC_N TEGRA_GPIO_PDD2
+#define USBO1_EN TEGRA_GPIO_PT5
+#define USBO1_OC_N TEGRA_GPIO_PT6
+
+#define WAKE1_MICO TEGRA_GPIO_PV1
+
+/* STMPE811 IRQs */
+#define STMPE811_IRQ_BASE TEGRA_NR_IRQS
+#define STMPE811_IRQ_END (STMPE811_IRQ_BASE + 22)
+
+#define TDIODE_OFFSET (10000) /* in millicelsius */
+#define TCRIT_LOCAL 95000 /* board temp to switch off PMIC in millicelsius*/
+
+/* External peripheral act as gpio */
+/* TPS6591x GPIOs */
+#define TPS6591X_GPIO_BASE TEGRA_NR_GPIOS
+#define TPS6591X_GPIO_0 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP0)
+#define TPS6591X_GPIO_1 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP1)
+#define TPS6591X_GPIO_2 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP2)
+#define TPS6591X_GPIO_3 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP3)
+#define TPS6591X_GPIO_4 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP4)
+#define TPS6591X_GPIO_5 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP5)
+#define TPS6591X_GPIO_6 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP6)
+#define TPS6591X_GPIO_7 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP7)
+#define TPS6591X_GPIO_8 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP8)
+#define TPS6591X_GPIO_END (TPS6591X_GPIO_BASE + TPS6591X_GPIO_NR)
+
+/*****************Interrupt tables ******************/
+/* External peripheral act as interrupt controller */
+/* TPS6591x IRQs */
+#define TPS6591X_IRQ_BASE STMPE811_IRQ_END
+#define TPS6591X_IRQ_END (TPS6591X_IRQ_BASE + 18)
+
+int apalis_t30_regulator_init(void);
+int apalis_t30_suspend_init(void);
+int apalis_t30_pinmux_init(void);
+int apalis_t30_panel_init(void);
+int apalis_t30_sensors_init(void);
+int apalis_t30_gpio_switch_regulator_init(void);
+int apalis_t30_pins_state_init(void);
+int apalis_t30_emc_init(void);
+int apalis_t30_power_off_init(void);
+int apalis_t30_edp_init(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/board-aruba-sdhci.c b/arch/arm/mach-tegra/board-aruba-sdhci.c
index cf29137b773f..678385f2b8bd 100644
--- a/arch/arm/mach-tegra/board-aruba-sdhci.c
+++ b/arch/arm/mach-tegra/board-aruba-sdhci.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-harmony-sdhci.c
+ * arch/arm/mach-tegra/board-aruba-sdhci.c
*
* Copyright (C) 2010 Google, Inc.
*
diff --git a/arch/arm/mach-tegra/board-cardhu-sdhci.c b/arch/arm/mach-tegra/board-cardhu-sdhci.c
index df7177fb34a7..6b8948b874ff 100644
--- a/arch/arm/mach-tegra/board-cardhu-sdhci.c
+++ b/arch/arm/mach-tegra/board-cardhu-sdhci.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-harmony-sdhci.c
+ * arch/arm/mach-tegra/board-cardhu-sdhci.c
*
* Copyright (C) 2010 Google, Inc.
* Copyright (C) 2011-2012 NVIDIA Corporation.
diff --git a/arch/arm/mach-tegra/board-colibri_t20-memory.c b/arch/arm/mach-tegra/board-colibri_t20-memory.c
new file mode 100644
index 000000000000..65b24bfa6544
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t20-memory.c
@@ -0,0 +1,464 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t20-memory.c
+ *
+ * Copyright (C) 2012 Toradex, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/memblock.h>
+
+#include "board-colibri_t20.h"
+#include "board.h"
+#include "tegra2_emc.h"
+
+/* Optimised timings for Colibri T20 256 MB */
+static const struct tegra_emc_table colibri_t20_emc_tables_nanya_333Mhz[] = {
+ {
+ .rate = 83250, /* SDRAM frequency */
+ .regs = {
+ 0x00000005, /* RC */
+ 0x00000011, /* RFC */
+ 0x00000004, /* RAS */
+ 0x00000002, /* RP */
+ 0x00000004, /* R2W */
+ 0x00000004, /* W2R */
+ 0x00000001, /* R2P */
+ 0x0000000a, /* W2P */
+ 0x00000002, /* RD_RCD */
+ 0x00000002, /* WR_RCD */
+ 0x00000001, /* RRD */
+ 0x00000001, /* REXT */
+ 0x00000003, /* WDV */
+ 0x00000004, /* QUSE */
+ 0x00000003, /* QRST */
+ 0x00000009, /* QSAFE */
+ 0x0000000c, /* RDV */
+ 0x0000025f, /* REFRESH */
+ 0x00000000, /* BURST_REFRESH_NUM */
+ 0x00000003, /* PDEX2WR */
+ 0x00000003, /* PDEX2RD */
+ 0x00000002, /* PCHG2PDEN */
+ 0x00000002, /* ACT2PDEN */
+ 0x00000001, /* AR2PDEN */
+ 0x00000008, /* RW2PDEN */
+ 0x000000c8, /* TXSR */
+ 0x00000003, /* TCKE */
+ 0x00000005, /* TFAW */
+ 0x00000003, /* TRPAB */
+ 0x00000006, /* TCLKSTABLE */
+ 0x00000002, /* TCLKSTOP */
+ 0x00000000, /* TREFBW */
+ 0x00000000, /* QUSE_EXTRA */
+ 0x00000002, /* FBIO_CFG6 */
+ 0x00000000, /* ODT_WRITE */
+ 0x00000000, /* ODT_READ */
+ 0x00000083, /* FBIO_CFG5 */
+ 0x00520006, /* CFG_DIG_DLL */
+ 0x00000010, /* DLL_XFORM_DQS */
+ 0x00000008, /* DLL_XFORM_QUSE */
+ 0x00000000, /* ZCAL_REF_CNT */
+ 0x00000000, /* ZCAL_WAIT_CNT */
+ 0x00000000, /* AUTO_CAL_INTERVAL */
+ 0x00000000, /* CFG_CLKTRIM_0 */
+ 0x00000000, /* CFG_CLKTRIM_1 */
+ 0x00000000, /* CFG_CLKTRIM_2 */
+ }
+ },
+ {
+ .rate = 125000, /* SDRAM frequency */
+ .regs = {
+ 0x00000008, /* RC */
+ 0x00000010, /* RFC */
+ 0x00000006, /* RAS */
+ 0x00000002, /* RP */
+ 0x00000004, /* R2W */
+ 0x00000004, /* W2R */
+ 0x00000001, /* R2P */
+ 0x0000000a, /* W2P */
+ 0x00000002, /* RD_RCD */
+ 0x00000002, /* WR_RCD */
+ 0x00000002, /* RRD */
+ 0x00000001, /* REXT */
+ 0x00000003, /* WDV */
+ 0x00000004, /* QUSE */
+ 0x00000003, /* QRST */
+ 0x00000009, /* QSAFE */
+ 0x0000000c, /* RDV */
+ 0x0000039f, /* REFRESH */
+ 0x00000000, /* BURST_REFRESH_NUM */
+ 0x00000003, /* PDEX2WR */
+ 0x00000003, /* PDEX2RD */
+ 0x00000002, /* PCHG2PDEN */
+ 0x00000002, /* ACT2PDEN */
+ 0x00000001, /* AR2PDEN */
+ 0x00000008, /* RW2PDEN */
+ 0x000000c8, /* TXSR */
+ 0x00000003, /* TCKE */
+ 0x00000007, /* TFAW */
+ 0x00000003, /* TRPAB */
+ 0x00000006, /* TCLKSTABLE */
+ 0x00000002, /* TCLKSTOP */
+ 0x00000000, /* TREFBW */
+ 0x00000000, /* QUSE_EXTRA */
+ 0x00000002, /* FBIO_CFG6 */
+ 0x00000000, /* ODT_WRITE */
+ 0x00000000, /* ODT_READ */
+ 0x00000083, /* FBIO_CFG5 */
+ 0x00510006, /* CFG_DIG_DLL */
+ 0x00000010, /* DLL_XFORM_DQS */
+ 0x00000008, /* DLL_XFORM_QUSE */
+ 0x00000000, /* ZCAL_REF_CNT */
+ 0x00000000, /* ZCAL_WAIT_CNT */
+ 0x00000000, /* AUTO_CAL_INTERVAL */
+ 0x00000000, /* CFG_CLKTRIM_0 */
+ 0x00000000, /* CFG_CLKTRIM_1 */
+ 0x00000000, /* CFG_CLKTRIM_2 */
+ }
+ },
+ {
+ .rate = 166500, /* SDRAM frequency */
+ .regs = {
+ 0x0000000a, /* RC */
+ 0x00000016, /* RFC */
+ 0x00000008, /* RAS */
+ 0x00000003, /* RP */
+ 0x00000004, /* R2W */
+ 0x00000004, /* W2R */
+ 0x00000002, /* R2P */
+ 0x0000000a, /* W2P */
+ 0x00000003, /* RD_RCD */
+ 0x00000003, /* WR_RCD */
+ 0x00000002, /* RRD */
+ 0x00000001, /* REXT */
+ 0x00000003, /* WDV */
+ 0x00000004, /* QUSE */
+ 0x00000003, /* QRST */
+ 0x00000009, /* QSAFE */
+ 0x0000000c, /* RDV */
+ 0x000004df, /* REFRESH */
+ 0x00000000, /* BURST_REFRESH_NUM */
+ 0x00000003, /* PDEX2WR */
+ 0x00000003, /* PDEX2RD */
+ 0x00000003, /* PCHG2PDEN */
+ 0x00000003, /* ACT2PDEN */
+ 0x00000001, /* AR2PDEN */
+ 0x00000009, /* RW2PDEN */
+ 0x000000c8, /* TXSR */
+ 0x00000003, /* TCKE */
+ 0x00000009, /* TFAW */
+ 0x00000004, /* TRPAB */
+ 0x00000006, /* TCLKSTABLE */
+ 0x00000002, /* TCLKSTOP */
+ 0x00000000, /* TREFBW */
+ 0x00000000, /* QUSE_EXTRA */
+ 0x00000002, /* FBIO_CFG6 */
+ 0x00000000, /* ODT_WRITE */
+ 0x00000000, /* ODT_READ */
+ 0x00000083, /* FBIO_CFG5 */
+ 0x004f0006, /* CFG_DIG_DLL */
+ 0x00000010, /* DLL_XFORM_DQS */
+ 0x00000008, /* DLL_XFORM_QUSE */
+ 0x00000000, /* ZCAL_REF_CNT */
+ 0x00000000, /* ZCAL_WAIT_CNT */
+ 0x00000000, /* AUTO_CAL_INTERVAL */
+ 0x00000000, /* CFG_CLKTRIM_0 */
+ 0x00000000, /* CFG_CLKTRIM_1 */
+ 0x00000000, /* CFG_CLKTRIM_2 */
+ }
+ },
+ {
+ .rate = 333000, /* SDRAM frequency */
+ .regs = {
+ 0x00000014, /* RC */
+ 0x0000002b, /* RFC */
+ 0x0000000f, /* RAS */
+ 0x00000005, /* RP */
+ 0x00000004, /* R2W */
+ 0x00000005, /* W2R */
+ 0x00000003, /* R2P */
+ 0x0000000a, /* W2P */
+ 0x00000005, /* RD_RCD */
+ 0x00000005, /* WR_RCD */
+ 0x00000004, /* RRD */
+ 0x00000001, /* REXT */
+ 0x00000003, /* WDV */
+ 0x00000004, /* QUSE */
+ 0x00000003, /* QRST */
+ 0x00000009, /* QSAFE */
+ 0x0000000c, /* RDV */
+ 0x000009ff, /* REFRESH */
+ 0x00000000, /* BURST_REFRESH_NUM */
+ 0x00000003, /* PDEX2WR */
+ 0x00000003, /* PDEX2RD */
+ 0x00000005, /* PCHG2PDEN */
+ 0x00000005, /* ACT2PDEN */
+ 0x00000001, /* AR2PDEN */
+ 0x0000000e, /* RW2PDEN */
+ 0x000000c8, /* TXSR */
+ 0x00000003, /* TCKE */
+ 0x00000011, /* TFAW */
+ 0x00000006, /* TRPAB */
+ 0x00000006, /* TCLKSTABLE */
+ 0x00000002, /* TCLKSTOP */
+ 0x00000000, /* TREFBW */
+ 0x00000000, /* QUSE_EXTRA */
+ 0x00000002, /* FBIO_CFG6 */
+ 0x00000000, /* ODT_WRITE */
+ 0x00000000, /* ODT_READ */
+ 0x00000083, /* FBIO_CFG5 */
+ 0x00380006, /* CFG_DIG_DLL */
+ 0x00000010, /* DLL_XFORM_DQS */
+ 0x00000008, /* DLL_XFORM_QUSE */
+ 0x00000000, /* ZCAL_REF_CNT */
+ 0x00000000, /* ZCAL_WAIT_CNT */
+ 0x00000000, /* AUTO_CAL_INTERVAL */
+ 0x00000000, /* CFG_CLKTRIM_0 */
+ 0x00000000, /* CFG_CLKTRIM_1 */
+ 0x00000000, /* CFG_CLKTRIM_2 */
+ }
+ },
+};
+
+/* Standard timings for Colibri T20 512 MB */
+static const struct tegra_emc_table colibri_t20_emc_tables_memphis_333Mhz[] = {
+ {
+ .rate = 83250, /* SDRAM frequency */
+ .regs = {
+ 0x00000005, /* RC */
+ 0x00000011, /* RFC */
+ 0x00000004, /* RAS */
+ 0x00000002, /* RP */
+ 0x00000004, /* R2W */
+ 0x00000004, /* W2R */
+ 0x00000001, /* R2P */
+ 0x0000000a, /* W2P */
+ 0x00000002, /* RD_RCD */
+ 0x00000002, /* WR_RCD */
+ 0x00000001, /* RRD */
+ 0x00000001, /* REXT */
+ 0x00000003, /* WDV */
+ 0x00000004, /* QUSE */
+ 0x00000003, /* QRST */
+ 0x00000009, /* QSAFE */
+ 0x0000000c, /* RDV */
+ 0x0000025f, /* REFRESH */
+ 0x00000000, /* BURST_REFRESH_NUM */
+ 0x00000003, /* PDEX2WR */
+ 0x00000003, /* PDEX2RD */
+ 0x00000002, /* PCHG2PDEN */
+ 0x00000002, /* ACT2PDEN */
+ 0x00000001, /* AR2PDEN */
+ 0x00000008, /* RW2PDEN */
+ 0x000000c8, /* TXSR */
+ 0x00000003, /* TCKE */
+ 0x00000005, /* TFAW */
+ 0x00000003, /* TRPAB */
+ 0x0000000c, /* TCLKSTABLE */
+ 0x00000002, /* TCLKSTOP */
+ 0x00000000, /* TREFBW */
+ 0x00000000, /* QUSE_EXTRA */
+ 0x00000002, /* FBIO_CFG6 */
+ 0x00000000, /* ODT_WRITE */
+ 0x00000000, /* ODT_READ */
+ 0x00000083, /* FBIO_CFG5 */
+ 0x00520006, /* CFG_DIG_DLL */
+ 0x00000010, /* DLL_XFORM_DQS */
+ 0x00000008, /* DLL_XFORM_QUSE */
+ 0x00000000, /* ZCAL_REF_CNT */
+ 0x00000000, /* ZCAL_WAIT_CNT */
+ 0x00000000, /* AUTO_CAL_INTERVAL */
+ 0x00000000, /* CFG_CLKTRIM_0 */
+ 0x00000000, /* CFG_CLKTRIM_1 */
+ 0x00000000, /* CFG_CLKTRIM_2 */
+ }
+ },
+ {
+ .rate = 125000, /* SDRAM frequency */
+ .regs = {
+ 0x00000008, /* RC */
+ 0x00000019, /* RFC */
+ 0x00000006, /* RAS */
+ 0x00000002, /* RP */
+ 0x00000004, /* R2W */
+ 0x00000004, /* W2R */
+ 0x00000001, /* R2P */
+ 0x0000000a, /* W2P */
+ 0x00000002, /* RD_RCD */
+ 0x00000002, /* WR_RCD */
+ 0x00000002, /* RRD */
+ 0x00000001, /* REXT */
+ 0x00000003, /* WDV */
+ 0x00000004, /* QUSE */
+ 0x00000003, /* QRST */
+ 0x00000009, /* QSAFE */
+ 0x0000000c, /* RDV */
+ 0x0000039f, /* REFRESH */
+ 0x00000000, /* BURST_REFRESH_NUM */
+ 0x00000003, /* PDEX2WR */
+ 0x00000003, /* PDEX2RD */
+ 0x00000002, /* PCHG2PDEN */
+ 0x00000002, /* ACT2PDEN */
+ 0x00000001, /* AR2PDEN */
+ 0x00000008, /* RW2PDEN */
+ 0x000000c8, /* TXSR */
+ 0x00000003, /* TCKE */
+ 0x00000007, /* TFAW */
+ 0x00000003, /* TRPAB */
+ 0x0000000c, /* TCLKSTABLE */
+ 0x00000002, /* TCLKSTOP */
+ 0x00000000, /* TREFBW */
+ 0x00000000, /* QUSE_EXTRA */
+ 0x00000002, /* FBIO_CFG6 */
+ 0x00000000, /* ODT_WRITE */
+ 0x00000000, /* ODT_READ */
+ 0x00000083, /* FBIO_CFG5 */
+ 0x00510006, /* CFG_DIG_DLL */
+ 0x00000010, /* DLL_XFORM_DQS */
+ 0x00000008, /* DLL_XFORM_QUSE */
+ 0x00000000, /* ZCAL_REF_CNT */
+ 0x00000000, /* ZCAL_WAIT_CNT */
+ 0x00000000, /* AUTO_CAL_INTERVAL */
+ 0x00000000, /* CFG_CLKTRIM_0 */
+ 0x00000000, /* CFG_CLKTRIM_1 */
+ 0x00000000, /* CFG_CLKTRIM_2 */
+ }
+ },
+ {
+ .rate = 166500, /* SDRAM frequency */
+ .regs = {
+ 0x0000000a, /* RC */
+ 0x00000021, /* RFC */
+ 0x00000008, /* RAS */
+ 0x00000003, /* RP */
+ 0x00000004, /* R2W */
+ 0x00000004, /* W2R */
+ 0x00000002, /* R2P */
+ 0x0000000a, /* W2P */
+ 0x00000003, /* RD_RCD */
+ 0x00000003, /* WR_RCD */
+ 0x00000002, /* RRD */
+ 0x00000001, /* REXT */
+ 0x00000003, /* WDV */
+ 0x00000004, /* QUSE */
+ 0x00000003, /* QRST */
+ 0x00000009, /* QSAFE */
+ 0x0000000c, /* RDV */
+ 0x000004df, /* REFRESH */
+ 0x00000000, /* BURST_REFRESH_NUM */
+ 0x00000003, /* PDEX2WR */
+ 0x00000003, /* PDEX2RD */
+ 0x00000003, /* PCHG2PDEN */
+ 0x00000003, /* ACT2PDEN */
+ 0x00000001, /* AR2PDEN */
+ 0x00000009, /* RW2PDEN */
+ 0x000000c8, /* TXSR */
+ 0x00000003, /* TCKE */
+ 0x00000009, /* TFAW */
+ 0x00000004, /* TRPAB */
+ 0x0000000c, /* TCLKSTABLE */
+ 0x00000002, /* TCLKSTOP */
+ 0x00000000, /* TREFBW */
+ 0x00000000, /* QUSE_EXTRA */
+ 0x00000002, /* FBIO_CFG6 */
+ 0x00000000, /* ODT_WRITE */
+ 0x00000000, /* ODT_READ */
+ 0x00000083, /* FBIO_CFG5 */
+ 0x004f0006, /* CFG_DIG_DLL */
+ 0x00000010, /* DLL_XFORM_DQS */
+ 0x00000008, /* DLL_XFORM_QUSE */
+ 0x00000000, /* ZCAL_REF_CNT */
+ 0x00000000, /* ZCAL_WAIT_CNT */
+ 0x00000000, /* AUTO_CAL_INTERVAL */
+ 0x00000000, /* CFG_CLKTRIM_0 */
+ 0x00000000, /* CFG_CLKTRIM_1 */
+ 0x00000000, /* CFG_CLKTRIM_2 */
+ }
+ },
+ {
+ .rate = 333000, /* SDRAM frequency */
+ .regs = {
+ 0x00000014, /* RC */
+ 0x00000041, /* RFC */
+ 0x0000000f, /* RAS */
+ 0x00000005, /* RP */
+ 0x00000004, /* R2W */
+ 0x00000005, /* W2R */
+ 0x00000003, /* R2P */
+ 0x0000000a, /* W2P */
+ 0x00000005, /* RD_RCD */
+ 0x00000005, /* WR_RCD */
+ 0x00000004, /* RRD */
+ 0x00000001, /* REXT */
+ 0x00000003, /* WDV */
+ 0x00000004, /* QUSE */
+ 0x00000003, /* QRST */
+ 0x00000009, /* QSAFE */
+ 0x0000000c, /* RDV */
+ 0x000009ff, /* REFRESH */
+ 0x00000000, /* BURST_REFRESH_NUM */
+ 0x00000003, /* PDEX2WR */
+ 0x00000003, /* PDEX2RD */
+ 0x00000005, /* PCHG2PDEN */
+ 0x00000005, /* ACT2PDEN */
+ 0x00000001, /* AR2PDEN */
+ 0x0000000e, /* RW2PDEN */
+ 0x000000c8, /* TXSR */
+ 0x00000003, /* TCKE */
+ 0x00000011, /* TFAW */
+ 0x00000006, /* TRPAB */
+ 0x0000000c, /* TCLKSTABLE */
+ 0x00000002, /* TCLKSTOP */
+ 0x00000000, /* TREFBW */
+ 0x00000000, /* QUSE_EXTRA */
+ 0x00000002, /* FBIO_CFG6 */
+ 0x00000000, /* ODT_WRITE */
+ 0x00000000, /* ODT_READ */
+ 0x00000083, /* FBIO_CFG5 */
+ 0x00380006, /* CFG_DIG_DLL */
+ 0x00000010, /* DLL_XFORM_DQS */
+ 0x00000008, /* DLL_XFORM_QUSE */
+ 0x00000000, /* ZCAL_REF_CNT */
+ 0x00000000, /* ZCAL_WAIT_CNT */
+ 0x00000000, /* AUTO_CAL_INTERVAL */
+ 0x00000000, /* CFG_CLKTRIM_0 */
+ 0x00000000, /* CFG_CLKTRIM_1 */
+ 0x00000000, /* CFG_CLKTRIM_2 */
+ }
+ },
+};
+
+static const struct tegra_emc_chip colibri_t20_emc_chips[] = {
+ {
+ .description = "Nanya NT5TU64M16GG 333MHz",
+ .table = colibri_t20_emc_tables_nanya_333Mhz,
+ .table_size = ARRAY_SIZE(colibri_t20_emc_tables_nanya_333Mhz)
+ },
+ {
+ .description = "MEMPHIS MEM2G16D2DABG 333MHz",
+ .table = colibri_t20_emc_tables_memphis_333Mhz,
+ .table_size = ARRAY_SIZE(colibri_t20_emc_tables_memphis_333Mhz)
+ },
+};
+
+int colibri_t20_emc_init(void)
+{
+ /* Assume less than 256 MB of kernel memory (e.g. physical memory minus
+ carveout and framebuffers) means we are running on a 256 MB module */
+ if (memblock_end_of_DRAM() < 256 * 1024 * 1024)
+ tegra_init_emc(&colibri_t20_emc_chips[0], 1);
+ else
+ tegra_init_emc(&colibri_t20_emc_chips[1], 1);
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/board-colibri_t20-panel.c b/arch/arm/mach-tegra/board-colibri_t20-panel.c
new file mode 100644
index 000000000000..4c11b6c7f6e1
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t20-panel.c
@@ -0,0 +1,473 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t20-panel.c
+ *
+ * Copyright (c) 2012, Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <asm/mach-types.h>
+
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/gpio.h>
+#include <linux/nvhost.h>
+#include <linux/nvmap.h>
+#include <linux/platform_device.h>
+#include <linux/pwm_backlight.h>
+#include <linux/regulator/consumer.h>
+#include <linux/resource.h>
+
+#include <mach/dc.h>
+#include <mach/fb.h>
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+
+#include "board.h"
+#include "board-colibri_t20.h"
+#include "devices.h"
+#include "gpio-names.h"
+#include "tegra2_host1x_devices.h"
+
+#ifndef COLIBRI_T20_VI
+#define colibri_t20_bl_enb TEGRA_GPIO_PT4 /* BL_ON */
+#endif
+#define colibri_t20_hdmi_hpd TEGRA_GPIO_PN7 /* HOTPLUG_DETECT */
+#ifdef IRIS
+#define iris_dac_psave TEGRA_GPIO_PA0 /* DAC_PSAVE# */
+#endif
+
+#ifdef CONFIG_TEGRA_DC
+static struct regulator *colibri_t20_hdmi_reg = NULL;
+static struct regulator *colibri_t20_hdmi_pll = NULL;
+#endif
+
+#ifndef COLIBRI_T20_VI
+static int colibri_t20_backlight_init(struct device *dev) {
+ int ret;
+
+ ret = gpio_request(colibri_t20_bl_enb, "BL_ON");
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_direction_output(colibri_t20_bl_enb, 1);
+ if (ret < 0)
+ gpio_free(colibri_t20_bl_enb);
+
+ return ret;
+};
+
+static void colibri_t20_backlight_exit(struct device *dev) {
+ gpio_set_value(colibri_t20_bl_enb, 0);
+ gpio_free(colibri_t20_bl_enb);
+}
+
+static int colibri_t20_backlight_notify(struct device *dev, int brightness)
+{
+ struct platform_pwm_backlight_data *pdata = dev->platform_data;
+
+ gpio_set_value(colibri_t20_bl_enb, !!brightness);
+
+ /* Unified TFT interface displays (e.g. EDT ET070080DH6) LEDCTRL pin
+ with inverted behaviour (e.g. 0V brightest vs. 3.3V darkest)
+ Note: brightness polarity display model specific */
+ if (brightness) return pdata->max_brightness - brightness;
+ else return brightness;
+}
+
+static int colibri_t20_disp1_check_fb(struct device *dev, struct fb_info *info);
+
+static struct platform_pwm_backlight_data colibri_t20_backlight_data = {
+#ifndef MECS_TELLURIUM
+ .pwm_id = 0, /* PWM<A> (PMFM_PWM0) */
+#else
+ .pwm_id = 2, /* PWM<C> (PMFM_PWM2) */
+#endif
+ .max_brightness = 255,
+ .dft_brightness = 127,
+ .pwm_period_ns = 1000000, /* 1 kHz */
+ .init = colibri_t20_backlight_init,
+ .exit = colibri_t20_backlight_exit,
+ .notify = colibri_t20_backlight_notify,
+ /* Only toggle backlight on fb blank notifications for disp1 */
+ .check_fb = colibri_t20_disp1_check_fb,
+};
+
+static struct platform_device colibri_t20_backlight_device = {
+ .name = "pwm-backlight",
+ .id = -1,
+ .dev = {
+ .platform_data = &colibri_t20_backlight_data,
+ },
+};
+#endif /* !COLIBRI_T20_VI */
+
+#ifdef CONFIG_TEGRA_DC
+static int colibri_t20_panel_enable(void)
+{
+#ifdef IRIS
+ gpio_set_value(iris_dac_psave, 1);
+#endif
+ return 0;
+}
+
+static int colibri_t20_panel_disable(void)
+{
+#ifdef IRIS
+ gpio_set_value(iris_dac_psave, 0);
+#endif
+ return 0;
+}
+
+static int colibri_t20_hdmi_enable(void)
+{
+ if (!colibri_t20_hdmi_reg) {
+ colibri_t20_hdmi_reg = regulator_get(NULL, "avdd_hdmi"); /* LD07 */
+ if (IS_ERR_OR_NULL(colibri_t20_hdmi_reg)) {
+ pr_err("hdmi: couldn't get regulator avdd_hdmi\n");
+ colibri_t20_hdmi_reg = NULL;
+ return PTR_ERR(colibri_t20_hdmi_reg);
+ }
+ }
+ regulator_enable(colibri_t20_hdmi_reg);
+
+ if (!colibri_t20_hdmi_pll) {
+ colibri_t20_hdmi_pll = regulator_get(NULL, "avdd_hdmi_pll"); /* LD08 */
+ if (IS_ERR_OR_NULL(colibri_t20_hdmi_pll)) {
+ pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n");
+ colibri_t20_hdmi_pll = NULL;
+ regulator_disable(colibri_t20_hdmi_reg);
+ colibri_t20_hdmi_reg = NULL;
+ return PTR_ERR(colibri_t20_hdmi_pll);
+ }
+ }
+ regulator_enable(colibri_t20_hdmi_pll);
+ return 0;
+}
+
+static int colibri_t20_hdmi_disable(void)
+{
+ regulator_disable(colibri_t20_hdmi_reg);
+ regulator_disable(colibri_t20_hdmi_pll);
+ return 0;
+}
+
+static struct resource colibri_t20_disp1_resources[] = {
+ {
+ .name = "irq",
+ .start = INT_DISPLAY_GENERAL,
+ .end = INT_DISPLAY_GENERAL,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "regs",
+ .start = TEGRA_DISPLAY_BASE,
+ .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fbmem",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource colibri_t20_disp2_resources[] = {
+ {
+ .name = "irq",
+ .start = INT_DISPLAY_B_GENERAL,
+ .end = INT_DISPLAY_B_GENERAL,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "regs",
+ .start = TEGRA_DISPLAY2_BASE,
+ .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fbmem",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "hdmi_regs",
+ .start = TEGRA_HDMI_BASE,
+ .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct tegra_fb_data colibri_t20_fb_data = {
+ .win = 0,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+static struct tegra_fb_data colibri_t20_hdmi_fb_data = {
+ .win = 0,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+static struct tegra_dc_out_pin colibri_t20_dc_out_pins[] = {
+ {
+ .name = TEGRA_DC_OUT_PIN_H_SYNC,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+ {
+ .name = TEGRA_DC_OUT_PIN_V_SYNC,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+ {
+ .name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+};
+
+static struct tegra_dc_out colibri_t20_disp1_out = {
+ .type = TEGRA_DC_OUT_RGB,
+ .parent_clk = "pll_p",
+ .parent_clk_backup = "pll_d",
+
+ .max_pixclock = KHZ2PICOS(162000),
+
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+ .depth = 18,
+ .dither = TEGRA_DC_ORDERED_DITHER,
+
+ /* Use 32-bit depth for android builds */
+#ifdef CONFIG_ANDROID
+ .default_mode = "640x480-32@60",
+#else /* CONFIG_ANDROID */
+ .default_mode = "640x480-16@60",
+#endif /* CONFIG_ANDROID */
+
+ .out_pins = colibri_t20_dc_out_pins,
+ .n_out_pins = ARRAY_SIZE(colibri_t20_dc_out_pins),
+
+ .enable = colibri_t20_panel_enable,
+ .disable = colibri_t20_panel_disable,
+};
+
+static struct tegra_dc_out colibri_t20_disp2_out = {
+ .type = TEGRA_DC_OUT_HDMI,
+ .flags = TEGRA_DC_OUT_HOTPLUG_HIGH,
+
+ .dcc_bus = 1,
+ .hotplug_gpio = colibri_t20_hdmi_hpd,
+
+ .max_pixclock = KHZ2PICOS(148500),
+
+ /* Use 32-bit depth for android builds */
+#ifdef CONFIG_ANDROID
+ .default_mode = "640x480-32@60",
+#else /* CONFIG_ANDROID */
+ .default_mode = "640x480-16@60",
+#endif /* CONFIG_ANDROID */
+
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+
+ .enable = colibri_t20_hdmi_enable,
+ .disable = colibri_t20_hdmi_disable,
+
+// .dither = TEGRA_DC_ORDERED_DITHER,
+};
+
+static struct tegra_dc_platform_data colibri_t20_disp1_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &colibri_t20_disp1_out,
+ .fb = &colibri_t20_fb_data,
+};
+
+static struct tegra_dc_platform_data colibri_t20_disp2_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &colibri_t20_disp2_out,
+ .fb = &colibri_t20_hdmi_fb_data,
+};
+
+static struct nvhost_device colibri_t20_disp1_device = {
+ .name = "tegradc",
+ .id = 0,
+ .resource = colibri_t20_disp1_resources,
+ .num_resources = ARRAY_SIZE(colibri_t20_disp1_resources),
+ .dev = {
+ .platform_data = &colibri_t20_disp1_pdata,
+ },
+};
+
+#ifndef COLIBRI_T20_VI
+static int colibri_t20_disp1_check_fb(struct device *dev, struct fb_info *info)
+{
+ return info->device == &colibri_t20_disp1_device.dev;
+}
+#endif /* !COLIBRI_T20_VI */
+
+static struct nvhost_device colibri_t20_disp2_device = {
+ .name = "tegradc",
+ .id = 1,
+ .resource = colibri_t20_disp2_resources,
+ .num_resources = ARRAY_SIZE(colibri_t20_disp2_resources),
+ .dev = {
+ .platform_data = &colibri_t20_disp2_pdata,
+ },
+};
+#else /* CONFIG_TEGRA_DC */
+static int colibri_t20_disp1_check_fb(struct device *dev, struct fb_info *info)
+{
+ return 0;
+}
+#endif /* CONFIG_TEGRA_DC */
+
+#if defined(CONFIG_TEGRA_NVMAP)
+static struct nvmap_platform_carveout colibri_t20_carveouts[] = {
+ [0] = NVMAP_HEAP_CARVEOUT_IRAM_INIT,
+ [1] = {
+ .name = "generic-0",
+ .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC,
+ .buddy_size = SZ_32K,
+ },
+};
+
+static struct nvmap_platform_data colibri_t20_nvmap_data = {
+ .carveouts = colibri_t20_carveouts,
+ .nr_carveouts = ARRAY_SIZE(colibri_t20_carveouts),
+};
+
+static struct platform_device colibri_t20_nvmap_device = {
+ .name = "tegra-nvmap",
+ .id = -1,
+ .dev = {
+ .platform_data = &colibri_t20_nvmap_data,
+ },
+};
+#endif /* CONFIG_TEGRA_NVMAP */
+
+static struct platform_device *colibri_t20_gfx_devices[] __initdata = {
+#if defined(CONFIG_TEGRA_NVMAP)
+ &colibri_t20_nvmap_device,
+#endif
+#ifndef COLIBRI_T20_VI
+#ifndef MECS_TELLURIUM
+ &tegra_pwfm0_device,
+#else
+ &tegra_pwfm2_device,
+#endif
+ &colibri_t20_backlight_device,
+#endif /* !COLIBRI_T20_VI */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/* put early_suspend/late_resume handlers here for the display in order
+ * to keep the code out of the display driver, keeping it closer to upstream
+ */
+struct early_suspend colibri_t20_panel_early_suspender;
+
+static void colibri_t20_panel_early_suspend(struct early_suspend *h)
+{
+ /* power down LCD, add use a black screen for HDMI */
+ if (num_registered_fb > 0)
+ fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
+ if (num_registered_fb > 1)
+ fb_blank(registered_fb[1], FB_BLANK_NORMAL);
+#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
+ cpufreq_store_default_gov();
+ cpufreq_change_gov(cpufreq_conservative_gov);
+#endif
+}
+
+static void colibri_t20_panel_late_resume(struct early_suspend *h)
+{
+ unsigned i;
+#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
+ cpufreq_restore_default_gov();
+#endif
+ for (i = 0; i < num_registered_fb; i++)
+ fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
+}
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+int __init colibri_t20_panel_init(void)
+{
+ int err;
+ struct resource __maybe_unused *res;
+ void __iomem *to_io;
+
+#ifdef IRIS
+ gpio_request(iris_dac_psave, "Iris DAC_PSAVE#");
+ gpio_direction_output(iris_dac_psave, 1);
+#endif /* IRIS */
+
+ /* enable hdmi hotplug gpio for hotplug detection */
+ gpio_request(colibri_t20_hdmi_hpd, "hdmi_hpd");
+ gpio_direction_input(colibri_t20_hdmi_hpd);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ colibri_t20_panel_early_suspender.suspend = colibri_t20_panel_early_suspend;
+ colibri_t20_panel_early_suspender.resume = colibri_t20_panel_late_resume;
+ colibri_t20_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ register_early_suspend(&colibri_t20_panel_early_suspender);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+#if defined(CONFIG_TEGRA_NVMAP)
+ colibri_t20_carveouts[1].base = tegra_carveout_start;
+ colibri_t20_carveouts[1].size = tegra_carveout_size;
+#endif /* CONFIG_TEGRA_NVMAP */
+
+#ifdef CONFIG_TEGRA_GRHOST
+ err = tegra2_register_host1x_devices();
+ if (err)
+ return err;
+#endif /* CONFIG_TEGRA_NVMAP */
+
+ err = platform_add_devices(colibri_t20_gfx_devices,
+ ARRAY_SIZE(colibri_t20_gfx_devices));
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
+ res = nvhost_get_resource_byname(&colibri_t20_disp1_device,
+ IORESOURCE_MEM, "fbmem");
+ res->start = tegra_fb_start;
+ res->end = tegra_fb_start + tegra_fb_size - 1;
+
+ res = nvhost_get_resource_byname(&colibri_t20_disp2_device,
+ IORESOURCE_MEM, "fbmem");
+ res->start = tegra_fb2_start;
+ res->end = tegra_fb2_start + tegra_fb2_size - 1;
+#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */
+
+ /* Make sure LVDS framebuffer is cleared. */
+ to_io = ioremap(tegra_fb_start, tegra_fb_size);
+ if (to_io) {
+ memset(to_io, 0, tegra_fb_size);
+ iounmap(to_io);
+ } else pr_err("%s: Failed to map LVDS framebuffer\n", __func__);
+
+ /* Make sure HDMI framebuffer is cleared.
+ Note: this seems to fix a tegradc.1 initialisation race in case of
+ framebuffer console as well. */
+ to_io = ioremap(tegra_fb2_start, tegra_fb2_size);
+ if (to_io) {
+ memset(to_io, 0, tegra_fb2_size);
+ iounmap(to_io);
+ } else pr_err("%s: Failed to map HDMI framebuffer\n", __func__);
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
+ if (!err)
+ err = nvhost_device_register(&colibri_t20_disp1_device);
+
+ if (!err)
+ err = nvhost_device_register(&colibri_t20_disp2_device);
+#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */
+
+ return err;
+}
diff --git a/arch/arm/mach-tegra/board-colibri_t20-pinmux.c b/arch/arm/mach-tegra/board-colibri_t20-pinmux.c
new file mode 100644
index 000000000000..85a28213dbe2
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t20-pinmux.c
@@ -0,0 +1,386 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t20-pinmux.c
+ *
+ * Copyright (C) 2011 Toradex, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <mach/pinmux.h>
+
+#include "board-colibri_t20.h"
+#include "gpio-names.h"
+
+#define DEFAULT_DRIVE(_name) \
+ { \
+ .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
+ .hsm = TEGRA_HSM_DISABLE, \
+ .schmitt = TEGRA_SCHMITT_ENABLE, \
+ .drive = TEGRA_DRIVE_DIV_1, \
+ .pull_down = TEGRA_PULL_31, \
+ .pull_up = TEGRA_PULL_31, \
+ .slew_rising = TEGRA_SLEW_SLOWEST, \
+ .slew_falling = TEGRA_SLEW_SLOWEST, \
+ }
+
+#define SET_DRIVE(_name, _hsm, _schmitt, _drive, _pulldn_drive, _pullup_drive, _pulldn_slew, _pullup_slew) \
+ { \
+ .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
+ .hsm = TEGRA_HSM_##_hsm, \
+ .schmitt = TEGRA_SCHMITT_##_schmitt, \
+ .drive = TEGRA_DRIVE_##_drive, \
+ .pull_down = TEGRA_PULL_##_pulldn_drive, \
+ .pull_up = TEGRA_PULL_##_pullup_drive, \
+ .slew_rising = TEGRA_SLEW_##_pulldn_slew, \
+ .slew_falling = TEGRA_SLEW_##_pullup_slew, \
+ }
+
+static __initdata struct tegra_drive_pingroup_config colibri_t20_drive_pinmux[] = {
+ DEFAULT_DRIVE(SDIO1),
+ DEFAULT_DRIVE(VI1),
+
+ SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+ SET_DRIVE(AT1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+ SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+ SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+ SET_DRIVE(VI2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+};
+
+static __initdata int colibri_t20_gpio_input_pinmux[] = {
+ /* SODIMM pin 152 tri-stating GMI_CLK as OWR can not be tri-stated */
+//currently reserved during board platform GPIO handling
+// TEGRA_GPIO_PK1, /* GMI_CLK multiplexed OWR */
+
+ /* Camera interface aka video input */
+#ifdef COLIBRI_T20_VI
+ TEGRA_GPIO_PA7, /* SDIO3_CMD multiplexed VI_D6 */
+ TEGRA_GPIO_PB4, /* SDIO3_DAT3 multiplexed VI_D7 */
+#else /* COLIBRI_T20_VI */
+ TEGRA_GPIO_PL4, /* VI_D6 multiplexed SDIO3_CMD */
+ TEGRA_GPIO_PL5, /* VI_D7 multiplexed SDIO3_DAT3 */
+#endif /* COLIBRI_T20_VI */
+
+ /* SODIMM pin 93 RDnWR */
+#if 1
+ TEGRA_GPIO_PW0, /* gated GMI_WR_N multiplexed LCD_CS1_N */
+#endif
+
+ /* SODIMM pin 44 L_BIAS configured as LCD data enable */
+#if 0
+ TEGRA_GPIO_PJ1, /* LCD_M1 multiplexed LCD_DE */
+#else
+ TEGRA_GPIO_PW1, /* LCD_DE multiplexed LCD_M1 */
+#endif
+
+ /* SODIMM pin 95 RDY */
+#if 1
+ TEGRA_GPIO_PI7, /* GMI_IORDY multiplexed GMI_WAIT */
+#else
+ TEGRA_GPIO_PI5, /* GMI_WAIT multiplexed GMI_IORDY */
+#endif
+
+ /* SODIMM pin 99 nPWE */
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+ TEGRA_GPIO_PZ3, /* gated GMI_WR_N multiplexed LCD_WR_N */
+#endif
+
+ /* 24-bit LCD lines */
+#if 0
+ TEGRA_GPIO_PM2, /* SPI2_CS0_N multiplexed LCD_D18 */
+ TEGRA_GPIO_PM3, /* SPI2_SCK multiplexed LCD_D19 */
+ TEGRA_GPIO_PM4, /* SPI2_MISO multiplexed LCD_D20 */
+ TEGRA_GPIO_PM5, /* SPI2_MOSI multiplexed LCD_D21 */
+ TEGRA_GPIO_PM6, /* DAP2_DOUT multiplexed LCD_D22 */
+ TEGRA_GPIO_PM7, /* DAP2_DIN multiplexed LCD_D23 */
+#else
+ TEGRA_GPIO_PX3, /* LCD_D18 multiplexed SPI2_CS0_N */
+ TEGRA_GPIO_PX2, /* LCD_D19 multiplexed SPI2_SCK */
+ TEGRA_GPIO_PX1, /* LCD_D20 multiplexed SPI2_MISO */
+ TEGRA_GPIO_PX0, /* LCD_D21 multiplexed SPI2_MOSI */
+ TEGRA_GPIO_PA5, /* LCD_D22 multiplexed DAP2_DOUT */
+ TEGRA_GPIO_PA4, /* LCD_D23 multiplexed DAP2_DIN */
+#endif
+};
+
+static __initdata struct tegra_pingroup_config colibri_t20_pinmux[] = {
+/* tegra_pingroup tegra_mux_func tegra_pullupdown tegra_tristate
+ TRISTATE here means output driver is tri-stated, even configuring GPIO function won't override this.
+ Tristating would significantly reduce I/O power consumption. */
+ /* nRESET_OUT de-asserted further down below, GPIO I3, I4 and I6 */
+ {TEGRA_PINGROUP_ATA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_ATB, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* nCSx, AD0, AD1, AD2, AD3, AD4, AD5, AD6 and AD7, nWR, nOE, GPIO K0, K1, K2, K3 and K4 */
+ {TEGRA_PINGROUP_ATC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* AD8, AD9, AD10 and AD11 */
+ {TEGRA_PINGROUP_ATD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* AD12, AD13, AD14 and AD15 */
+ {TEGRA_PINGROUP_ATE, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* WM9715L XTL_IN */
+//audio sync clk could be either AC97 or PLLA_OUT0
+//SYNC_CLK_DOUBLER_ENB: Enable audio sync clk doubler.
+// {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_AUDIO_SYNC, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* USB3340 REFCLK */
+ {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* CLK_32K_IN pin pull-up/down control only */
+ {TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK,TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO N0, N1, N2 and N3 */
+ {TEGRA_PINGROUP_DAP1, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO A2 and A3 */
+ {TEGRA_PINGROUP_DAP2, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* A13, A14, A15 and A16, GPIO P4, P5, P6 and P7 */
+ {TEGRA_PINGROUP_DAP4, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* DDC pins pulled up to avoid issues if no FFC cable is connected to X3 */
+ {TEGRA_PINGROUP_DDC, TEGRA_MUX_I2C2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ /* Pull-up/down control only */
+ {TEGRA_PINGROUP_DDRC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO D5 */
+ {TEGRA_PINGROUP_DTA, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO T2 and T3 as KEY_FIND */
+#ifdef CONFIG_KEYBOARD_GPIO
+ {TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+#else
+ {TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+#endif
+ {TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO L0, L1, L2, L3, L6 and L7
+ GPIO L4 and L5 multiplexed with PWM<A> and PWM<D> */
+ {TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* AX88772B V_BUS, WM9715L PENDOWN, GPIO A0, BB4 as KEY_VOLUMEUP and BB5 as KEY_VOLUMEDOWN */
+#ifdef CONFIG_KEYBOARD_GPIO
+ {TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+#else
+ {TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+#endif
+ /* GPIO BB2 as KEY_BACK and BB3 as KEY_HOME */
+#ifdef CONFIG_KEYBOARD_GPIO
+ {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+#else
+ {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+#endif
+ {TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* MM_CD */
+ {TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI_INT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* BT_TXD, BT_RXD, BT_CTS and BT_RTS, GPIO K7 */
+ {TEGRA_PINGROUP_GMC, TEGRA_MUX_UARTD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_GMD, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO AA4, AA5, AA6 and AA7 */
+#ifndef SDHCI_8BIT
+ {TEGRA_PINGROUP_GME, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+#else
+ {TEGRA_PINGROUP_GME, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+#endif
+ /* A6, A7, A8, A9, A10, A11 and A12, GPIO U6 */
+ {TEGRA_PINGROUP_GPU, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* AX88772B RESET_N and EXTWAKEUP_N */
+ {TEGRA_PINGROUP_GPV, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* HDMI HOTPLUG_DETECT */
+ {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* A0 */
+ {TEGRA_PINGROUP_IRRX, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* A1 */
+ {TEGRA_PINGROUP_IRTX, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_KBCA, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_KBCB, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_KBCC, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_KBCD, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_KBCE, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_KBCF, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO N4 */
+ {TEGRA_PINGROUP_LCSN, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD10, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD11, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD12, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD13, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD14, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD15, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD16, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD17, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD3, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD4, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD5, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD6, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD7, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD8, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LD9, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO N6 */
+ {TEGRA_PINGROUP_LDC, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LHP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LHS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* Multiplexed RDnWR */
+ {TEGRA_PINGROUP_LM0, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LM1, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO B2 */
+ {TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LPW1, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* Multiplexed gated nPWE */
+ {TEGRA_PINGROUP_LSC1, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO Z4 */
+ {TEGRA_PINGROUP_LSCK, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO N5 */
+ {TEGRA_PINGROUP_LSDA, TEGRA_MUX_DISPLAYB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO Z2 */
+ {TEGRA_PINGROUP_LSDI, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LSPI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* THERMD_ALERT */
+ {TEGRA_PINGROUP_LVP0, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LVP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* OWR multiplexed with GMI_CLK */
+ {TEGRA_PINGROUP_OWC, TEGRA_MUX_OWR, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+
+ /* Following five are for specific PMC pin pull-up/down control only */
+ /* CLK_32K_OUT */
+ {TEGRA_PINGROUP_PMCA, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* SYS_CLK_REQ */
+ {TEGRA_PINGROUP_PMCB, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* CORE_PWR_REQ */
+ {TEGRA_PINGROUP_PMCC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* CPU_PWR_REQ */
+ {TEGRA_PINGROUP_PMCD, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* PWR_INT_N pulled up */
+ {TEGRA_PINGROUP_PMCE, TEGRA_MUX_NONE, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+
+ /* Gating RDnWR, nPWE through GPIOs further down below */
+ {TEGRA_PINGROUP_PTA, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* PWM3 */
+ /* PWM<D> multiplexed with CIF_DD<6> */
+ {TEGRA_PINGROUP_SDB, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO B6 and B7, PWM0 and PWM1 */
+ /* PWM<A> multiplexed with CIF_DD<7> */
+ {TEGRA_PINGROUP_SDC, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* PWM2 */
+ {TEGRA_PINGROUP_SDD, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_UARTA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+
+ /* SPI4 */
+ {TEGRA_PINGROUP_SLXA, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SLXC, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SLXD, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SLXK, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+
+ /* GPIO K6 as KEY_MENU multiplexed ACC1_DETECT */
+ {TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* GPIO K5 multiplexed USB1_VBUS (USBC_DET) */
+ {TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+
+ /* X0, X1, X2, X3, X4, X5, X6 and X7 */
+ {TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPIB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPID, TEGRA_MUX_SPI1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPIE, TEGRA_MUX_SPI1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPIF, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+
+ /* USBH_PEN */
+ {TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* USBH_OC */
+ {TEGRA_PINGROUP_SPIH, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+
+ /* ULPI data pins pulled up like on NVIDIA's Ventana reference platform */
+ {TEGRA_PINGROUP_UAA, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_UAB, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+
+ /* WM9715L RESET#, USB3340 RESETB, WM9715L GENIRQ and GPIO V3 as KEY_POWER */
+#ifdef CONFIG_KEYBOARD_GPIO
+ {TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+#else
+ {TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+#endif
+ /* STD_TXD and STD_RXD */
+ {TEGRA_PINGROUP_UAD, TEGRA_MUX_IRDA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* A2 and A3 */
+ {TEGRA_PINGROUP_UCA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* A4 and A5 */
+ {TEGRA_PINGROUP_UCB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_UDA, TEGRA_MUX_ULPI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+
+ /* Following two are for specific DDR pin pull-up/down control only */
+ {TEGRA_PINGROUP_XM2C, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+};
+
+#ifdef GMI_32BIT
+/* 32-bit wide data and 28-bit wide address bus, more chip selects */
+static __initdata struct tegra_pingroup_config colibri_t20_widebus_pinmux[] = {
+ /* D28, D29, D30 and D31 */
+ {TEGRA_PINGROUP_DAP1, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* AD20, AD21, AD22 and AD23 */
+ {TEGRA_PINGROUP_GMA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* AD16, AD17, AD18 and AD19 */
+ {TEGRA_PINGROUP_GMC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ /* nCS0 and nCS1 */
+ {TEGRA_PINGROUP_GMD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+#ifndef SDHCI_8BIT
+ /* AD24, AD25, AD26 and AD27 */
+ {TEGRA_PINGROUP_GME, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+#endif
+};
+#endif /* GMI_32BIT */
+
+int __init colibri_t20_pinmux_init(void)
+{
+ int i;
+
+ tegra_pinmux_config_table(colibri_t20_pinmux, ARRAY_SIZE(colibri_t20_pinmux));
+#ifdef GMI_32BIT
+ tegra_pinmux_config_table(colibri_t20_widebus_pinmux, ARRAY_SIZE(colibri_t20_widebus_pinmux));
+#endif
+ tegra_drive_pinmux_config_table(colibri_t20_drive_pinmux,
+ ARRAY_SIZE(colibri_t20_drive_pinmux));
+
+ /* configure GPIO inputs on multiplexed balls to tri-state specific functions
+ instead of tri-stating whole groups */
+ for(i = 0; i < ARRAY_SIZE(colibri_t20_gpio_input_pinmux); i++) {
+ gpio_request(colibri_t20_gpio_input_pinmux[i], "function tri-stated");
+ gpio_direction_input(colibri_t20_gpio_input_pinmux[i]);
+ }
+
+ /* un-resetting external devices via SODIMM pin 87 nRESET_OUT */
+ gpio_request(TEGRA_GPIO_PI4, "SODIMM 87 nRESET_OUT");
+ gpio_direction_output(TEGRA_GPIO_PI4, 1);
+
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+ /* not tri-stating GMI_WR_N on SODIMM pin 99 nPWE */
+ gpio_request(TEGRA_GPIO_PT5, "GMI_WR_N on 99");
+ gpio_direction_output(TEGRA_GPIO_PT5, 0);
+#else /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
+ /* tri-stating GMI_WR_N on SODIMM pin 99 nPWE */
+ gpio_request(TEGRA_GPIO_PT5, "no GMI_WR_N on 99");
+ gpio_direction_output(TEGRA_GPIO_PT5, 1);
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
+
+ /* not tri-stating GMI_WR_N on SODIMM pin 93 RDnWR */
+ gpio_request(TEGRA_GPIO_PT6, "GMI_WR_N on 93 RDnWR");
+ gpio_direction_output(TEGRA_GPIO_PT6, 0);
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/board-colibri_t20-power.c b/arch/arm/mach-tegra/board-colibri_t20-power.c
new file mode 100644
index 000000000000..fb6e8e8e1bf3
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t20-power.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2011 Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/mfd/tps6586x.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+
+#include "board-colibri_t20.h"
+#include "board.h"
+#include "fuse.h"
+#include "gpio-names.h"
+#include "pm.h"
+
+#define PMC_CTRL 0x0
+#define PMC_CTRL_INTR_LOW (1 << 17)
+
+/* VDD_CORE_1.2V */
+static struct regulator_consumer_supply tps658621_sm0_supply[] = {
+ REGULATOR_SUPPLY("vdd_core", NULL),
+};
+
+/* VDD_CPU_1.0V */
+static struct regulator_consumer_supply tps658621_sm1_supply[] = {
+ REGULATOR_SUPPLY("vdd_cpu", NULL),
+};
+
+/* VDD_DDR2_1.8V, LAN AX88772B VCC18A_ and NAND K9K8G08U0B VCC */
+static struct regulator_consumer_supply tps658621_sm2_supply[] = {
+ REGULATOR_SUPPLY("vdd_sm2", NULL),
+};
+
+/* unused */
+static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
+ REGULATOR_SUPPLY("vdd_ldo0", NULL),
+};
+
+/* AVDD_PLL_1.1V and +3.3V_ENABLE_N switching via FET: AVDD_AUDIO_S and +3.3V:
+SMSC USB3340 VBAT, VDDIO
+VCC_LAN
+VDDIO_AUDIO
+VDDIO_BB
+VDDIO_LCD
+VDDIO_NAND
+VDDIO_SDIO
+VDDIO_UART
+VDDIO_VI */
+static struct regulator_consumer_supply tps658621_ldo1_supply[] = {
+ REGULATOR_SUPPLY("vdd_ldo1", NULL),
+ REGULATOR_SUPPLY("avdd_pll", NULL),
+};
+
+/* VDD_RTC_1.2V */
+static struct regulator_consumer_supply tps658621_ldo2_supply[] = {
+ REGULATOR_SUPPLY("vdd_ldo2", NULL),
+ REGULATOR_SUPPLY("vdd_rtc", NULL),
+ REGULATOR_SUPPLY("vdd_aon", NULL),
+};
+
+/* unused */
+static struct regulator_consumer_supply tps658621_ldo3_supply[] = {
+ REGULATOR_SUPPLY("vdd_ldo3", NULL),
+};
+
+/* VDDIO_SYS_1.8V and VDDIO_PMIC */
+static struct regulator_consumer_supply tps658621_ldo4_supply[] = {
+ REGULATOR_SUPPLY("vdd_ldo4", NULL),
+ REGULATOR_SUPPLY("avdd_osc", NULL),
+};
+
+/* +3.3V_USB switched via FET: AVDD_USB,
+ +3.3V_FUSE switched via FET on FUSE_EN# (PMIC GPIO3)*/
+static struct regulator_consumer_supply tps658621_ldo5_supply[] = {
+ REGULATOR_SUPPLY("vdd_ldo5", NULL),
+ REGULATOR_SUPPLY("avdd_usb", NULL),
+ REGULATOR_SUPPLY("avdd_usb_pll", NULL),
+ /* fuse via separate GPIO FET (FUSE_ENABLE_N) */
+ REGULATOR_SUPPLY("vdd_fuse", NULL),
+};
+
+/* AVDD_VDAC_2.85V */
+static struct regulator_consumer_supply tps658621_ldo6_supply[] = {
+ /* Off after boot, needs to be explicitly turned on! */
+ REGULATOR_SUPPLY("vdd_ldo6", NULL),
+ REGULATOR_SUPPLY("avdd_vdac", NULL),
+};
+
+/* AVDD_HDMI_3.3V */
+static struct regulator_consumer_supply tps658621_ldo7_supply[] = {
+ REGULATOR_SUPPLY("vdd_ldo7", NULL),
+ REGULATOR_SUPPLY("avdd_hdmi", NULL),
+};
+
+/* AVDD_HDMI_PLL_1.8V */
+static struct regulator_consumer_supply tps658621_ldo8_supply[] = {
+ REGULATOR_SUPPLY("vdd_ldo8", NULL),
+ REGULATOR_SUPPLY("avdd_hdmi_pll", NULL),
+};
+
+/* VDDIO_RX_DDR_2.85V */
+static struct regulator_consumer_supply tps658621_ldo9_supply[] = {
+ REGULATOR_SUPPLY("vdd_ldo9", NULL),
+ REGULATOR_SUPPLY("vdd_ddr_rx", NULL),
+};
+
+static struct tps6586x_settings sm0_config = {
+ .sm_pwm_mode = PWM_DEFAULT_VALUE,
+ .slew_rate = SLEW_RATE_3520UV_PER_SEC,
+};
+
+static struct tps6586x_settings sm1_config = {
+ /*
+ * Current TPS6586x is known for having a voltage glitch if current load
+ * changes from low to high in auto PWM/PFM mode for CPU's Vdd line.
+ */
+ .sm_pwm_mode = PWM_ONLY,
+ .slew_rate = SLEW_RATE_3520UV_PER_SEC,
+};
+
+#define REGULATOR_INIT(_id, _minmv, _maxmv, on, config) \
+ { \
+ .constraints = { \
+ .min_uV = (_minmv)*1000, \
+ .max_uV = (_maxmv)*1000, \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL | \
+ REGULATOR_MODE_STANDBY), \
+ .valid_ops_mask = (REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_STATUS | \
+ REGULATOR_CHANGE_VOLTAGE), \
+ .always_on = on, \
+ .apply_uV = 1, \
+ }, \
+ .num_consumer_supplies = ARRAY_SIZE(tps658621_##_id##_supply),\
+ .consumer_supplies = tps658621_##_id##_supply, \
+ .driver_data = config, \
+ }
+
+#define ON 1
+#define OFF 0
+
+static struct regulator_init_data sm0_data = REGULATOR_INIT(sm0, 725, 1500, ON, &sm0_config);
+static struct regulator_init_data sm1_data = REGULATOR_INIT(sm1, 725, 1500, ON, &sm1_config);
+static struct regulator_init_data sm2_data = REGULATOR_INIT(sm2, 1700, 2475, ON, NULL);
+static struct regulator_init_data ldo0_data = REGULATOR_INIT(ldo0, 1200, 3300, OFF, NULL);
+static struct regulator_init_data ldo1_data = REGULATOR_INIT(ldo1, 725, 1500, ON, NULL);
+static struct regulator_init_data ldo2_data = REGULATOR_INIT(ldo2, 725, 1500, OFF, NULL);
+static struct regulator_init_data ldo3_data = REGULATOR_INIT(ldo3, 1250, 3300, OFF, NULL);
+static struct regulator_init_data ldo4_data = REGULATOR_INIT(ldo4, 1700, 2475, ON, NULL);
+static struct regulator_init_data ldo5_data = REGULATOR_INIT(ldo5, 1250, 3300, ON, NULL);
+static struct regulator_init_data ldo6_data = REGULATOR_INIT(ldo6, 2850, 2850, OFF, NULL);
+static struct regulator_init_data ldo7_data = REGULATOR_INIT(ldo7, 3300, 3300, OFF, NULL);
+static struct regulator_init_data ldo8_data = REGULATOR_INIT(ldo8, 1800, 1800, OFF, NULL);
+static struct regulator_init_data ldo9_data = REGULATOR_INIT(ldo9, 1250, 3300, OFF, NULL);
+
+static struct tps6586x_rtc_platform_data rtc_data = {
+ .irq = TEGRA_NR_IRQS + TPS6586X_INT_RTC_ALM1,
+ .start = {
+ .year = 2009,
+ .month = 1,
+ .day = 1,
+ },
+ .cl_sel = TPS6586X_RTC_CL_SEL_1_5PF /* use lowest (external 20pF cap) */
+};
+
+#define TPS_REG(_id, _data) \
+ { \
+ .id = TPS6586X_ID_##_id, \
+ .name = "tps6586x-regulator", \
+ .platform_data = _data, \
+ }
+
+static struct tps6586x_subdev_info tps_devs[] = {
+ TPS_REG(SM_0, &sm0_data),
+ TPS_REG(SM_1, &sm1_data),
+ TPS_REG(SM_2, &sm2_data),
+ TPS_REG(LDO_0, &ldo0_data),
+ TPS_REG(LDO_1, &ldo1_data),
+ TPS_REG(LDO_2, &ldo2_data),
+ TPS_REG(LDO_3, &ldo3_data),
+ TPS_REG(LDO_4, &ldo4_data),
+ TPS_REG(LDO_5, &ldo5_data),
+ TPS_REG(LDO_6, &ldo6_data),
+ TPS_REG(LDO_7, &ldo7_data),
+ TPS_REG(LDO_8, &ldo8_data),
+ TPS_REG(LDO_9, &ldo9_data),
+ {
+ .id = 0,
+ .name = "tps6586x-rtc",
+ .platform_data = &rtc_data,
+ },
+};
+
+static struct tps6586x_platform_data tps_platform = {
+ .irq_base = TPS6586X_INT_BASE,
+ .num_subdevs = ARRAY_SIZE(tps_devs),
+ .subdevs = tps_devs,
+ .gpio_base = TPS6586X_GPIO_BASE,
+ /* full PMIC power off decreases power consumption
+ but reset won't force a re-boot anymore */
+ .use_power_off = true,
+};
+
+static struct i2c_board_info __initdata colibri_t20_regulators[] = {
+ {
+ I2C_BOARD_INFO("tps6586x", 0x34),
+ .irq = INT_EXTERNAL_PMU,
+ .platform_data = &tps_platform,
+ },
+};
+
+static void colibri_t20_board_suspend(int lp_state, enum suspend_stage stg)
+{
+ if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_SUSPEND_BEFORE_CPU))
+ tegra_console_uart_suspend();
+}
+
+static void colibri_t20_board_resume(int lp_state, enum resume_stage stg)
+{
+ if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_RESUME_AFTER_CPU))
+ tegra_console_uart_resume();
+}
+
+static struct tegra_suspend_platform_data colibri_t20_suspend_data = {
+ /*
+ * Check power on time and crystal oscillator start time
+ * for appropriate settings.
+ */
+ .cpu_timer = 2000,
+ .cpu_off_timer = 100,
+ .suspend_mode = TEGRA_SUSPEND_LP1,
+ .core_timer = 0x7e7e,
+ .core_off_timer = 0xf,
+ .corereq_high = false,
+ .sysclkreq_high = true,
+ .board_suspend = colibri_t20_board_suspend,
+ .board_resume = colibri_t20_board_resume,
+};
+
+int __init colibri_t20_regulator_init(void)
+{
+ void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+ u32 pmc_ctrl;
+#if 0
+//currently LP0 is anyway not supported
+ void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
+ u32 minor;
+
+ minor = (readl(chip_id) >> 16) & 0xf;
+ /* A03 (but not A03p) chips do not support LP0 */
+ if (minor == 3 && !(tegra_spare_fuse(18) || tegra_spare_fuse(19)))
+ colibri_t20_suspend_data.suspend_mode = TEGRA_SUSPEND_LP1;
+#endif
+
+ /* configure the power management controller to trigger PMU
+ * interrupts when low */
+ pmc_ctrl = readl(pmc + PMC_CTRL);
+ writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);
+
+ i2c_register_board_info(4, colibri_t20_regulators, ARRAY_SIZE(colibri_t20_regulators));
+
+//none of the Tegra 2 boards currently do this
+// regulator_has_full_constraints();
+
+ tegra_init_suspend(&colibri_t20_suspend_data);
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/board-colibri_t20.c b/arch/arm/mach-tegra/board-colibri_t20.c
new file mode 100644
index 000000000000..470cc004165a
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t20.c
@@ -0,0 +1,1579 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t20.c
+ *
+ * Copyright (c) 2011-2013 Toradex, Inc.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <linux/can/platform/mcp251x.h>
+#include <linux/can/platform/sja1000.h>
+#include <linux/clk.h>
+#include <linux/colibri_usb.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio_keys.h>
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/leds_pwm.h>
+#include <linux/lm95245.h>
+#include <linux/memblock.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/serial_8250.h>
+#include <linux/spi/spi.h>
+#if defined(CONFIG_SPI_GPIO) || defined(CONFIG_SPI_GPIO_MODULE)
+#include <linux/spi/spi_gpio.h>
+#endif
+#include <linux/tegra_uart.h>
+#include <linux/wm97xx.h>
+
+#include <mach/gpio.h>
+#include <mach/nand.h>
+#include <mach/sdhci.h>
+#include <mach/usb_phy.h>
+#include <mach/w1.h>
+
+#include <media/soc_camera.h>
+#include <media/tegra_v4l2_camera.h>
+#include <linux/input/fusion_F0710A.h>
+
+#include "board-colibri_t20.h"
+#include "board.h"
+#include "clock.h"
+#include "cpu-tegra.h"
+#include "devices.h"
+#include "gpio-names.h"
+#include "pm.h"
+#include "wakeups-t2.h"
+
+//from former drivers/mtd/maps/tegra_nor.h
+#define TEGRA_GMI_PHYS 0x70009000
+#define TEGRA_GMI_BASE IO_TO_VIRT(TEGRA_GMI_PHYS)
+#define TEGRA_SNOR_CONFIG_REG (TEGRA_GMI_BASE + 0x00)
+
+//from drivers/mtd/maps/tegra_nor.c
+#define __BITMASK0(len) (BIT(len) - 1)
+#define REG_FIELD(val, start, len) (((val) & __BITMASK0(len)) << (start))
+
+#define TEGRA_SNOR_CONFIG_GO BIT(31)
+#define TEGRA_SNOR_CONFIG_SNOR_CS(val) REG_FIELD((val), 4, 3)
+
+/* ADC */
+
+static struct wm97xx_batt_pdata colibri_t20_adc_pdata = {
+ .batt_aux = WM97XX_AUX_ID1, /* AD0 - ANALOG_IN0 */
+ .temp_aux = WM97XX_AUX_ID2, /* AD1 - ANALOG_IN1 */
+ .charge_gpio = -1,
+ .batt_div = 1,
+ .batt_mult = 1,
+ .temp_div = 1,
+ .temp_mult = 1,
+ .batt_name = "colibri_t20-analog_inputs",
+};
+
+static struct wm97xx_pdata colibri_t20_wm97xx_pdata = {
+ .batt_pdata = &colibri_t20_adc_pdata,
+};
+
+/* Audio */
+
+static struct platform_device colibri_t20_audio_device = {
+ .name = "colibri_t20-snd-wm9715l",
+ .id = 0,
+};
+
+void *get_colibri_t20_audio_platform_data(void)
+{
+ return &colibri_t20_wm97xx_pdata;
+}
+EXPORT_SYMBOL(get_colibri_t20_audio_platform_data);
+
+/* Camera */
+
+#ifdef CONFIG_TEGRA_CAMERA
+static struct platform_device tegra_camera = {
+ .name = "tegra_camera",
+ .id = -1,
+};
+#endif /* CONFIG_TEGRA_CAMERA */
+
+#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE)
+static void tegra_camera_disable(struct nvhost_device *ndev)
+{
+}
+
+static int tegra_camera_enable(struct nvhost_device *ndev)
+{
+ return 0;
+}
+
+static struct tegra_camera_platform_data tegra_camera_platform_data = {
+ .disable_camera = tegra_camera_disable,
+ .enable_camera = tegra_camera_enable,
+ .flip_h = 0,
+ .flip_v = 0,
+ .port = TEGRA_CAMERA_PORT_VIP,
+};
+
+#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE)
+static struct i2c_board_info camera_i2c_max9526 = {
+ I2C_BOARD_INFO("max9526", 0x21),
+};
+
+static struct soc_camera_link iclink_max9526 = {
+ .board_info = &camera_i2c_max9526,
+ .bus_id = -1, /* This must match the .id of tegra_vi01_device */
+ .i2c_adapter_id = 0,
+};
+
+static struct platform_device soc_camera_max9526 = {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &iclink_max9526,
+ },
+};
+#endif /* CONFIG_SOC_CAMERA_MAX9526 | CONFIG_SOC_CAMERA_MAX9526_MODULE */
+
+#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE)
+static struct i2c_board_info camera_i2c_adv7180 = {
+ I2C_BOARD_INFO("adv7180", 0x21),
+};
+
+static struct soc_camera_link iclink_adv7180 = {
+ .board_info = &camera_i2c_adv7180,
+ .bus_id = -1, /* This must match the .id of tegra_vi01_device */
+ .i2c_adapter_id = 0,
+};
+
+static struct platform_device soc_camera_adv7180 = {
+ .name = "soc-camera-pdrv",
+ .id = 1,
+ .dev = {
+ .platform_data = &iclink_adv7180,
+ },
+};
+#endif /* CONFIG_VIDEO_ADV7180 | CONFIG_VIDEO_ADV7180_MODULE */
+#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */
+
+/* CAN */
+#if ((defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)) && \
+ (defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)))
+ #error either enable MCP251X or SJA1000 but not both
+#endif
+
+#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)
+/* Colibri EvalBoard V3.1a/MECS Tellurium xPOD CAN module featuring MCP2515 SPI CAN controller */
+
+#ifdef MECS_TELLURIUM_XPOD2
+#define CAN_CS_GPIO TEGRA_GPIO_PB7 /* SSPFRM2 */
+#define CAN_INTERRUPT_GPIO TEGRA_GPIO_PK3 /* active low interrupt (MCP2515 nINT) */
+#define CAN_RESET_GPIO TEGRA_GPIO_PK2 /* active high reset (not MCP2515 nRESET) */
+#else
+#define CAN_INTERRUPT_GPIO TEGRA_GPIO_PA0 /* active low interrupt (MCP2515 nINT) */
+#define CAN_RESET_GPIO TEGRA_GPIO_PK4 /* active high reset (not MCP2515 nRESET) */
+#endif
+
+static int __init colibri_t20_mcp2515_setup(struct spi_device *spi)
+{
+ int gpio_status;
+
+ printk("Colibri EvalBoard V3.1a/MECS Tellurium xPOD CAN Initialisation\n");
+
+ /* configure MCP2515 reset line as output and pull high into reset */
+ gpio_status = gpio_request(CAN_RESET_GPIO, "CAN_RESET_GPIO");
+ if (gpio_status < 0)
+ pr_warning("CAN_RESET_GPIO request GPIO FAILED\n");
+ gpio_status = gpio_direction_output(CAN_RESET_GPIO, 1);
+ if (gpio_status < 0)
+ pr_warning("CAN_RESET_GPIO request GPIO DIRECTION FAILED\n");
+
+ udelay(2);
+
+ /* pull out of reset */
+ gpio_set_value(CAN_RESET_GPIO, 0);
+
+ return 0;
+}
+
+static struct mcp251x_platform_data mcp251x_pdata = {
+ .board_specific_setup = colibri_t20_mcp2515_setup,
+ .oscillator_frequency = 16000000,
+ .power_enable = NULL,
+ .transceiver_enable = NULL
+};
+
+static struct spi_board_info mcp251x_board_info[] = {
+ {
+#ifndef MECS_TELLURIUM_XPOD2
+ .bus_num = 3,
+#else
+ .bus_num = 4,
+#endif
+ .chip_select = 0,
+#ifdef MECS_TELLURIUM_XPOD2
+ .controller_data = (void *) CAN_CS_GPIO,
+#else
+// .controller_data = ,
+#endif
+ .max_speed_hz = 10000000,
+ .modalias = "mcp2515",
+ .platform_data = &mcp251x_pdata,
+ },
+};
+
+static void __init colibri_t20_mcp2515_can_init(void)
+{
+ mcp251x_board_info[0].irq = gpio_to_irq(CAN_INTERRUPT_GPIO);
+ spi_register_board_info(mcp251x_board_info, ARRAY_SIZE(mcp251x_board_info));
+}
+#else /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+#define colibri_t20_mcp2515_can_init() do {} while (0)
+#endif /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+#define CAN_BASE_TEG 0xd0000000 /* GMI_CS4_N */
+static struct resource colibri_can_resource[] = {
+ [0] = {
+ .start = CAN_BASE_TEG, /* address */
+ .end = CAN_BASE_TEG + 0xff, /* data */
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* interrupt assigned during initialisation */
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+ }
+};
+
+static struct sja1000_platform_data colibri_can_platdata = {
+ .osc_freq = 24000000,
+ .ocr = (OCR_MODE_NORMAL | OCR_TX0_PUSHPULL),
+ .cdr = CDR_CLK_OFF | /* Clock off (CLKOUT pin) */
+ CDR_CBP, /* CAN input comparator bypass */
+};
+
+static struct platform_device colibri_can_device = {
+ .name = "sja1000_platform",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(colibri_can_resource),
+ .resource = colibri_can_resource,
+ .dev = {
+ .platform_data = &colibri_can_platdata,
+ }
+};
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
+
+/* Clocks */
+static struct tegra_clk_init_table colibri_t20_clk_init_table[] __initdata = {
+ /* name parent rate enabled */
+ {"blink", "clk_32k", 32768, false},
+ /* SMSC3340 REFCLK 24 MHz */
+ {"pll_p_out4", "pll_p", 24000000, true},
+ {"pwm", "clk_m", 0, false},
+ {"spdif_out", "pll_a_out0", 0, false},
+
+//required otherwise getting disabled by "Disabling clocks left on by
+//bootloader" stage
+ {"uarta", "pll_p", 216000000, true},
+
+//required otherwise uses pll_p_out4 as parent and changing its rate to 72 MHz
+ {"sclk", "pll_p_out3", 108000000, true},
+
+ /* AC97 incl. touch (note: unfortunately no clk source mux exists) */
+ {"ac97", "pll_a_out0", 24576000, true},
+
+ /* WM9715L XTL_IN 24.576 MHz */
+//[ 0.372722] Unable to set parent pll_a_out0 of clock cdev1: -38
+// {"cdev1", "pll_a_out0", 24576000, true},
+// {"pll_a_out0", "pll_a", 24576000, true},
+
+ {"vde", "pll_c", 240000000, false},
+
+ {"ndflash", "pll_p", 108000000, false},
+ {"nor", "pll_p", 86500000, true},
+
+//[ 2.284308] kernel BUG at drivers/spi/spi-tegra.c:254!
+//[ 2.289454] Unable to handle kernel NULL pointer dereference at virtual
+// address 00000000
+ {"sbc4", "pll_p", 12000000, false},
+
+ {NULL, NULL, 0, 0},
+};
+
+/* GPIO */
+
+static struct gpio colibri_t20_gpios[] = {
+#if !defined(IRIS) && !defined(CONFIG_CAN_MCP251X) && \
+ !defined(CONFIG_CAN_MCP251X_MODULE) && \
+ !defined(CONFIG_CAN_SJA1000) && \
+ !defined(CONFIG_CAN_SJA1000_MODULE)
+//conflicts with CAN interrupt on Colibri Evaluation Board and MECS Tellurium
+//xPOD1 CAN
+//conflicts with DAC_PSAVE# on Iris
+ {TEGRA_GPIO_PA0, GPIOF_IN, "SODIMM pin 73"},
+#endif
+ {TEGRA_GPIO_PA2, GPIOF_IN, "SODIMM pin 186"},
+ {TEGRA_GPIO_PA3, GPIOF_IN, "SODIMM pin 184"},
+ {TEGRA_GPIO_PB2, GPIOF_IN, "SODIMM pin 154"},
+#if !defined(CONFIG_SPI_GPIO) && !defined(CONFIG_SPI_GPIO_MODULE)
+//conflicts with MECS Tellurium xPOD2 SSPCLK2
+ {TEGRA_GPIO_PB6, GPIOF_IN, "SODIMM pin 55"},
+#endif
+#ifndef MECS_TELLURIUM_XPOD2
+//conflicts with MECS Tellurium xPOD2 SSPFRM2
+ {TEGRA_GPIO_PB7, GPIOF_IN, "SODIMM pin 63"},
+#endif
+#ifndef COLIBRI_T20_VI
+ {TEGRA_GPIO_PD5, GPIOF_IN, "SODI-98, Iris X16-13"},
+ {TEGRA_GPIO_PD6, GPIOF_IN, "SODIMM pin 81"},
+ {TEGRA_GPIO_PD7, GPIOF_IN, "SODIMM pin 94"},
+#endif
+ {TEGRA_GPIO_PI3, GPIOF_IN, "SODIMM pin 130"},
+ {TEGRA_GPIO_PI6, GPIOF_IN, "SODIMM pin 132"},
+//conflicts with GMI_ADV_N used for multiplexed address/data bus
+ {TEGRA_GPIO_PK0, GPIOF_IN, "SODIMM pin 150"},
+//multiplexed OWR
+ {TEGRA_GPIO_PK1, GPIOF_IN, "SODIMM pin 152"},
+#if !defined(CONFIG_CAN_MCP251X) && !defined(CONFIG_CAN_MCP251X_MODULE)
+//conflicts with CAN reset on MECS Tellurium xPOD1 CAN
+ {TEGRA_GPIO_PK4, GPIOF_IN, "SODIMM pin 106"},
+#endif
+// {TEGRA_GPIO_PK5, GPIOF_IN, "USBC_DET"},
+#ifndef CONFIG_KEYBOARD_GPIO
+//conflicts with menu key
+ {TEGRA_GPIO_PK6, GPIOF_IN, "SODIMM pin 135"},
+#endif
+#ifndef COLIBRI_T20_VI
+ {TEGRA_GPIO_PL0, GPIOF_IN, "SOD-101, Iris X16-16"},
+ {TEGRA_GPIO_PL1, GPIOF_IN, "SOD-103, Iris X16-15"},
+//conflicts with Ethernet interrupt on Protea
+ {TEGRA_GPIO_PL2, GPIOF_IN, "SODI-79, Iris X16-19"},
+ {TEGRA_GPIO_PL3, GPIOF_IN, "SODI-97, Iris X16-17"},
+ {TEGRA_GPIO_PL6, GPIOF_IN, "SODI-85, Iris X16-18"},
+ {TEGRA_GPIO_PL7, GPIOF_IN, "SODIMM pin 65"},
+#endif
+
+//multiplexed SPI2_CS0_N, SPI2_MISO, SPI2_MOSI and SPI2_SCK
+ {TEGRA_GPIO_PM2, GPIOF_IN, "SODIMM pin 136"},
+ {TEGRA_GPIO_PM3, GPIOF_IN, "SODIMM pin 138"},
+ {TEGRA_GPIO_PM4, GPIOF_IN, "SODIMM pin 140"},
+ {TEGRA_GPIO_PM5, GPIOF_IN, "SODIMM pin 142"},
+
+#ifndef GMI_32BIT
+ {TEGRA_GPIO_PN0, GPIOF_IN, "SODIMM pin 174"},
+ {TEGRA_GPIO_PN1, GPIOF_IN, "SODIMM pin 176"},
+ {TEGRA_GPIO_PN2, GPIOF_IN, "SODIMM pin 178"},
+ {TEGRA_GPIO_PN3, GPIOF_IN, "SODIMM pin 180"},
+#endif
+ {TEGRA_GPIO_PN4, GPIOF_IN, "SODIMM pin 160"},
+ {TEGRA_GPIO_PN5, GPIOF_IN, "SODIMM pin 158"},
+ {TEGRA_GPIO_PN6, GPIOF_IN, "SODIMM pin 162"},
+//conflicts with ADDRESS13
+ {TEGRA_GPIO_PP4, GPIOF_IN, "SODIMM pin 120"},
+//conflicts with ADDRESS14
+ {TEGRA_GPIO_PP5, GPIOF_IN, "SODIMM pin 122"},
+//conflicts with ADDRESS15
+ {TEGRA_GPIO_PP6, GPIOF_IN, "SODIMM pin 124"},
+ {TEGRA_GPIO_PP7, GPIOF_IN, "SODIMM pin 188"},
+#ifndef COLIBRI_T20_VI
+ {TEGRA_GPIO_PT0, GPIOF_IN, "SODIMM pin 96"},
+ {TEGRA_GPIO_PT1, GPIOF_IN, "SODIMM pin 75"},
+#endif
+ {TEGRA_GPIO_PT2, GPIOF_IN, "SODIMM pin 69"},
+#ifndef CONFIG_KEYBOARD_GPIO
+//conflicts with find key
+ {TEGRA_GPIO_PT3, GPIOF_IN, "SODIMM pin 77"},
+#endif
+//conflicts with BL_ON
+// {TEGRA_GPIO_PT4, GPIOF_IN, "SODIMM pin 71"},
+//conflicts with ADDRESS12
+ {TEGRA_GPIO_PU6, GPIOF_IN, "SODIMM pin 118"},
+#ifndef CONFIG_KEYBOARD_GPIO
+//conflicts with power key (WAKE1)
+ {TEGRA_GPIO_PV3, GPIOF_IN, "SODI-45, Iris X16-20"},
+#endif
+
+ {TEGRA_GPIO_PX4, GPIOF_IN, "SODIMM pin 134"},
+ {TEGRA_GPIO_PX6, GPIOF_IN, "102, I X13 ForceOFF#"},
+ {TEGRA_GPIO_PX7, GPIOF_IN, "104, I X14 ForceOFF#"},
+ {TEGRA_GPIO_PZ2, GPIOF_IN, "SODIMM pin 156"},
+ {TEGRA_GPIO_PZ4, GPIOF_IN, "SODIMM pin 164"},
+#if !defined(GMI_32BIT) && !defined SDHCI_8BIT
+ {TEGRA_GPIO_PAA4, GPIOF_IN, "SODIMM pin 166"},
+ {TEGRA_GPIO_PAA5, GPIOF_IN, "SODIMM pin 168"},
+ {TEGRA_GPIO_PAA6, GPIOF_IN, "SODIMM pin 170"},
+ {TEGRA_GPIO_PAA7, GPIOF_IN, "SODIMM pin 172"},
+#endif
+#ifndef CONFIG_KEYBOARD_GPIO
+//conflicts with back key
+ {TEGRA_GPIO_PBB2, GPIOF_IN, "SOD-133, Iris X16-14"},
+//conflicts with home key
+ {TEGRA_GPIO_PBB3, GPIOF_IN, "SODIMM pin 127"},
+//conflicts with volume up key
+ {TEGRA_GPIO_PBB4, GPIOF_IN, "SODIMM pin 22"},
+//conflicts with volume down key
+ {TEGRA_GPIO_PBB5, GPIOF_IN, "SODIMM pin 24"},
+#endif
+};
+
+static void colibri_t20_gpio_init(void)
+{
+ int i = 0;
+ int length = sizeof(colibri_t20_gpios) / sizeof(struct gpio);
+ int err = 0;
+
+ for (i = 0; i < length; i++) {
+ err = gpio_request_one(colibri_t20_gpios[i].gpio,
+ colibri_t20_gpios[i].flags,
+ colibri_t20_gpios[i].label);
+
+ if (err) {
+ pr_warning("gpio_request(%s) failed, err = %d",
+ colibri_t20_gpios[i].label, err);
+ } else {
+ gpio_export(colibri_t20_gpios[i].gpio, true);
+ }
+ }
+}
+
+/*
+ * Fusion touch screen GPIOs (using Toradex display/touch adapater)
+ * Iris X16-38, SODIMM pin 28 (PWM B), pen down interrupt
+ * Iris X16-39, SODIMM pin 30 (PWM C), reset
+ * gpio_request muxes the GPIO function automatically, we only have to make
+ * sure input/output muxing is done here...
+ */
+static struct fusion_f0710a_init_data colibri_fusion_pdata = {
+ .pinmux_fusion_pins = NULL,
+ .gpio_int = TEGRA_GPIO_PB5, /* SO-DIMM 28: Pen down interrupt */
+ .gpio_reset = TEGRA_GPIO_PA6, /* SO-DIMM 30: Reset interrupt */
+};
+
+/* I2C */
+
+/* GEN1_I2C: I2C_SDA/SCL on SODIMM pin 194/196 (e.g. RTC on carrier board) */
+static struct i2c_board_info colibri_t20_i2c_bus1_board_info[] __initdata = {
+ {
+ /* M41T0M6 real time clock on Iris carrier board */
+ I2C_BOARD_INFO("rtc-ds1307", 0x68),
+ .type = "m41t00",
+ },
+ {
+ /* TouchRevolution Fusion 7 and 10 multi-touch controller */
+ I2C_BOARD_INFO("fusion_F0710A", 0x10),
+ .platform_data = &colibri_fusion_pdata,
+ },
+};
+
+static struct tegra_i2c_platform_data colibri_t20_i2c1_platform_data = {
+ .adapter_nr = 0,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {400000, 0},
+ .bus_count = 1,
+ .scl_gpio = {I2C_SCL, 0},
+ .sda_gpio = {I2C_SDA, 0},
+ .slave_addr = 0x00FC,
+};
+
+/* GEN2_I2C: unused */
+
+/* DDC_CLOCK/DATA on X3 pin 15/16 (e.g. display EDID) */
+static const struct tegra_pingroup_config i2c2_ddc = {
+ .pingroup = TEGRA_PINGROUP_DDC,
+ .func = TEGRA_MUX_I2C2,
+};
+
+static struct tegra_i2c_platform_data colibri_t20_i2c2_platform_data = {
+ .adapter_nr = 1,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {10000, 10000},
+ .bus_count = 1,
+ .slave_addr = 0x00FC,
+};
+
+/* PWR_I2C: power I2C to PMIC and temperature sensor */
+
+static void lm95245_probe_callback(struct device *dev);
+
+static struct lm95245_platform_data colibri_t20_lm95245_pdata = {
+ .enable_os_pin = true,
+ .probe_callback = lm95245_probe_callback,
+};
+
+static struct i2c_board_info colibri_t20_i2c_bus4_board_info[] __initdata = {
+ {
+ /* LM95245 temperature sensor */
+ I2C_BOARD_INFO("lm95245", 0x4c),
+ .platform_data = &colibri_t20_lm95245_pdata,
+ },
+};
+
+static struct tegra_i2c_platform_data colibri_t20_dvc_platform_data = {
+ .adapter_nr = 4,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {400000, 0},
+ .bus_count = 1,
+ .is_dvc = true,
+ .scl_gpio = {PWR_I2C_SCL, 0},
+ .sda_gpio = {PWR_I2C_SDA, 0},
+};
+
+static void colibri_t20_i2c_init(void)
+{
+ tegra_i2c_device1.dev.platform_data = &colibri_t20_i2c1_platform_data;
+ tegra_i2c_device2.dev.platform_data = &colibri_t20_i2c2_platform_data;
+ tegra_i2c_device4.dev.platform_data = &colibri_t20_dvc_platform_data;
+
+ platform_device_register(&tegra_i2c_device1);
+ platform_device_register(&tegra_i2c_device2);
+ platform_device_register(&tegra_i2c_device4);
+
+ i2c_register_board_info(0, colibri_t20_i2c_bus1_board_info,
+ ARRAY_SIZE(colibri_t20_i2c_bus1_board_info));
+ i2c_register_board_info(4, colibri_t20_i2c_bus4_board_info,
+ ARRAY_SIZE(colibri_t20_i2c_bus4_board_info));
+}
+
+/* Keys
+ * Note: active-low means pull-ups required on carrier board resp. via
+ * pin-muxing
+ * Note2: power-key active-high due to EvalBoard v3.1a having 100 K pull-down
+ * on SODIMM pin 45
+ * Note3: menu-key active-high due to strong pull-down on multiplexed
+ * ACC1_DETECT
+ * Note4: Wake keys need to be supported by hardware, see wakeups-t2.h
+ */
+
+#ifdef CONFIG_KEYBOARD_GPIO
+#define GPIO_KEY(_id, _gpio, _lowactive, _iswake) \
+ { \
+ .code = _id, \
+ .gpio = TEGRA_GPIO_##_gpio, \
+ .active_low = _lowactive, \
+ .desc = #_id, \
+ .type = EV_KEY, \
+ .wakeup = _iswake, \
+ .debounce_interval = 10, \
+ }
+
+static struct gpio_keys_button colibri_t20_keys[] = {
+ GPIO_KEY(KEY_FIND, PT3, 1, 0), /* SODIMM pin 77 */
+ GPIO_KEY(KEY_HOME, PBB3, 1, 0), /* SODIMM pin 127 */
+ GPIO_KEY(KEY_BACK, PBB2, 1, 0), /* SODIMM pin 133,
+ Iris X16-14 */
+ GPIO_KEY(KEY_VOLUMEUP, PBB4, 1, 0), /* SODIMM pin 22 */
+ GPIO_KEY(KEY_VOLUMEDOWN, PBB5, 1, 0), /* SODIMM pin 24 */
+ GPIO_KEY(KEY_POWER, PV3, 0, 1), /* SODIMM pin 45,
+ Iris X16-20 */
+ GPIO_KEY(KEY_MENU, PK6, 0, 0), /* SODIMM pin 135 */
+};
+
+#define PMC_WAKE_STATUS 0x14
+
+static int colibri_t20_wakeup_key(void)
+{
+ unsigned long status =
+ readl(IO_ADDRESS(TEGRA_PMC_BASE) + PMC_WAKE_STATUS);
+
+ return (status & (1 << TEGRA_WAKE_GPIO_PV3)) ?
+ KEY_POWER : KEY_RESERVED;
+}
+
+static struct gpio_keys_platform_data colibri_t20_keys_platform_data = {
+ .buttons = colibri_t20_keys,
+ .nbuttons = ARRAY_SIZE(colibri_t20_keys),
+ .wakeup_key = colibri_t20_wakeup_key,
+};
+
+static struct platform_device colibri_t20_keys_device = {
+ .name = "gpio-keys",
+ .id = 0,
+ .dev = {
+ .platform_data = &colibri_t20_keys_platform_data,
+ },
+};
+#endif /* CONFIG_KEYBOARD_GPIO */
+
+#ifndef GMI_32BIT
+/* MMC/SD */
+
+static struct tegra_sdhci_platform_data colibri_t20_sdhci_platform_data = {
+ .cd_gpio = MMC_CD,
+#ifndef SDHCI_8BIT
+ .is_8bit = 0,
+#else
+ .is_8bit = 1,
+#endif
+ .power_gpio = -1,
+ .wp_gpio = -1,
+};
+
+int __init colibri_t20_sdhci_init(void)
+{
+ tegra_sdhci_device4.dev.platform_data =
+ &colibri_t20_sdhci_platform_data;
+ platform_device_register(&tegra_sdhci_device4);
+
+ return 0;
+}
+#endif /* !GMI_32BIT */
+
+/* NAND */
+
+static struct tegra_nand_chip_parms nand_chip_parms[] = {
+ /* Micron MT29F4G08ABBDAH4 */
+ [0] = {
+ .vendor_id = 0x2C,
+ .device_id = 0xAC,
+ .read_id_fourth_byte = 0x15,
+ .capacity = 512,
+ .timing = {
+ .trp = 12,
+ .trh = 10, /* tREH */
+ .twp = 12,
+ .twh = 10,
+ .tcs = 20, /* Max(tCS, tCH, tALS, tALH) */
+ .twhr = 80,
+ .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */
+ .twb = 100,
+ .trp_resp = 12, /* tRP */
+ .tadl = 70,
+ },
+ },
+ /* Micron MT29F4G08ABBEAH4 */
+ [1] = {
+ .vendor_id = 0x2C,
+ .device_id = 0xAC,
+ .read_id_fourth_byte = 0x26,
+ .capacity = 512,
+ .timing = {
+ .trp = 15,
+ .trh = 10, /* tREH */
+ .twp = 15,
+ .twh = 10,
+ .tcs = 25, /* Max(tCS, tCH, tALS, tALH) */
+ .twhr = 80,
+ .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */
+ .twb = 100,
+ .trp_resp = 15, /* tRP */
+ .tadl = 100,
+ },
+ },
+ /* Micron MT29F8G08ABCBB on Colibri T20 before V1.2 */
+ [2] = {
+ .vendor_id = 0x2C,
+ .device_id = 0x38,
+ .read_id_fourth_byte = 0x26,
+ .capacity = 1024,
+ .timing = {
+ /* timing mode 4 */
+ .trp = 12,
+ .trh = 10, /* tREH */
+ .twp = 12,
+ .twh = 10,
+ .tcs = 20, /* Max(tCS, tCH, tALS, tALH) */
+ .twhr = 60,
+ .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */
+ .twb = 100,
+ .trp_resp = 12, /* tRP */
+ .tadl = 70,
+ },
+ },
+ /* Micron MT29F8G08ADBDAH4 */
+ [3] = {
+ .vendor_id = 0x2C,
+ .device_id = 0xA3,
+ .read_id_fourth_byte = 0x15,
+ .capacity = 1024,
+ .timing = {
+ .trp = 12,
+ .trh = 10, /* tREH */
+ .twp = 12,
+ .twh = 10,
+ .tcs = 20, /* Max(tCS, tCH, tALS, tALH) */
+ .twhr = 80,
+ .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */
+ .twb = 100,
+ .trp_resp = 12, /* tRP */
+ .tadl = 70,
+ },
+ },
+ /* Micron MT29F8G08ABBCA */
+ [4] = {
+ .vendor_id = 0x2C,
+ .device_id = 0xA3,
+ .read_id_fourth_byte = 0x26,
+ .capacity = 1024,
+ .timing = {
+ .trp = 15,
+ .trh = 10, /* tREH */
+ .twp = 15,
+ .twh = 10,
+ .tcs = 25, /* Max(tCS, tCH, tALS, tALH) */
+ .twhr = 80,
+ .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */
+ .twb = 100,
+ .trp_resp = 15, /* tRP */
+ .tadl = 100,
+ },
+ },
+ /* Samsung K9K8G08U0B */
+ [5] = {
+ .vendor_id = 0xec,
+ .device_id = 0xd3,
+ .read_id_fourth_byte = 0x95,
+ .capacity = 1024,
+ .timing = {
+ .trp = 12, /* tRP, ND_nRE pulse width */
+ .trh = 100, /* tRHZ, ND_nRE high
+ duration */
+ .twp = 12, /* tWP, ND_nWE pulse time */
+ .twh = 10, /* tWH, ND_nWE high duration */
+ .tcs = 20, /* Max(tCS, tCH, tALS, tALH) */
+ .twhr = 60, /* tWHR, ND_nWE high to ND_nRE
+ low delay for status read */
+ .tcr_tar_trr = 20, /* Max(tCR, tAR, tRR) */
+ .twb = 100,
+ .trp_resp = 12, /* tRP */
+ .tadl = 70,
+ },
+ },
+};
+
+struct tegra_nand_platform colibri_t20_nand_data = {
+ .max_chips = 8,
+ .chip_parms = nand_chip_parms,
+ .nr_chip_parms = ARRAY_SIZE(nand_chip_parms),
+ .wp_gpio = NAND_WP_N,
+};
+
+static struct resource resources_nand[] = {
+ [0] = {
+ .start = INT_NANDFLASH,
+ .end = INT_NANDFLASH,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tegra_nand_device = {
+ .name = "tegra_nand",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_nand),
+ .resource = resources_nand,
+ .dev = {
+ .platform_data = &colibri_t20_nand_data,
+ },
+};
+
+/* PWM LEDs */
+static struct led_pwm tegra_leds_pwm[] = {
+#ifdef MECS_TELLURIUM
+ {
+ .name = "PWM<A>",
+ .pwm_id = 0,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+#endif /* MECS_TELLURIUM */
+ {
+ .name = "PWM<B>",
+ .pwm_id = 1,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+#ifndef MECS_TELLURIUM
+ {
+ .name = "PWM<C>",
+ .pwm_id = 2,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+#endif /* !MECS_TELLURIUM */
+ {
+ .name = "PWM<D>",
+ .pwm_id = 3,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+};
+
+static struct led_pwm_platform_data tegra_leds_pwm_data = {
+ .num_leds = ARRAY_SIZE(tegra_leds_pwm),
+ .leds = tegra_leds_pwm,
+};
+
+static struct platform_device tegra_led_pwm_device = {
+ .name = "leds_pwm",
+ .id = -1,
+ .dev = {
+ .platform_data = &tegra_leds_pwm_data,
+ },
+};
+
+/* RTC */
+
+#ifdef CONFIG_RTC_DRV_TEGRA
+static struct resource tegra_rtc_resources[] = {
+ [0] = {
+ .start = TEGRA_RTC_BASE,
+ .end = TEGRA_RTC_BASE + TEGRA_RTC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = INT_RTC,
+ .end = INT_RTC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tegra_rtc_device = {
+ .name = "tegra_rtc",
+ .id = -1,
+ .resource = tegra_rtc_resources,
+ .num_resources = ARRAY_SIZE(tegra_rtc_resources),
+};
+#endif /* CONFIG_RTC_DRV_TEGRA */
+
+/* SPI */
+
+#if defined(CONFIG_SPI_GPIO) || defined(CONFIG_SPI_GPIO_MODULE)
+#ifdef MECS_TELLURIUM_XPOD2
+struct spi_gpio_platform_data xpod2_spi_platform_data = {
+ .sck = TEGRA_GPIO_PB6, /* SSPCLK2 */
+ .mosi = TEGRA_GPIO_PW2, /* SSPTXD2 */
+ .miso = TEGRA_GPIO_PW3, /* SSPRXD2 */
+ .num_chipselect = 1,
+};
+
+static struct platform_device xpod2_spi_device = {
+ .name = "spi_gpio",
+ .id = 4,
+ .dev = {
+ .platform_data = &xpod2_spi_platform_data,
+ }
+};
+#endif /* MECS_TELLURIUM_XPOD2 */
+#endif /* CONFIG_SPI_GPIO | CONFIG_SPI_GPIO_MODULE */
+
+#if defined(CONFIG_SPI_TEGRA) && defined(CONFIG_SPI_SPIDEV)
+static struct spi_board_info tegra_spi_devices[] __initdata = {
+ {
+ .bus_num = 3, /* SPI4: Colibri SSP */
+#if !defined(CONFIG_CAN_MCP251X) && !defined(CONFIG_CAN_MCP251X_MODULE)
+ .chip_select = 0,
+#else /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */
+ .chip_select = 1,
+#endif /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */
+ .irq = 0,
+ .max_speed_hz = 50000000,
+ .modalias = "spidev",
+ .mode = SPI_MODE_0,
+ .platform_data = NULL,
+ },
+};
+
+static void __init colibri_t20_register_spidev(void)
+{
+ spi_register_board_info(tegra_spi_devices,
+ ARRAY_SIZE(tegra_spi_devices));
+}
+#else /* CONFIG_SPI_TEGRA & CONFIG_SPI_SPIDEV */
+#define colibri_t20_register_spidev() do {} while (0)
+#endif /* CONFIG_SPI_TEGRA & CONFIG_SPI_SPIDEV */
+
+/* Thermal throttling
+ Note: As our hardware only allows triggering an interrupt on
+ over-temperature shutdown we first use it to catch entering throttle
+ and only then set it up to catch an actual over-temperature shutdown.
+ While throttling we setup a workqueue to catch leaving it again. */
+
+static int colibri_t20_shutdown_temp = 115000;
+static int colibri_t20_throttle_hysteresis = 3000;
+static int colibri_t20_throttle_temp = 90000;
+static struct device *lm95245_device = NULL;
+static int thermd_alert_irq_disabled = 0;
+struct work_struct thermd_alert_work;
+struct workqueue_struct *thermd_alert_workqueue;
+
+/* Over-temperature shutdown OS pin GPIO interrupt handler */
+static irqreturn_t thermd_alert_irq(int irq, void *data)
+{
+ disable_irq_nosync(irq);
+ thermd_alert_irq_disabled = 1;
+ queue_work(thermd_alert_workqueue, &thermd_alert_work);
+
+ return IRQ_HANDLED;
+}
+
+/* Gets both entered by THERMD_ALERT GPIO interrupt as well as re-scheduled
+ while throttling. */
+static void thermd_alert_work_func(struct work_struct *work)
+{
+ int temp = 0;
+
+ lm95245_get_remote_temp(lm95245_device, &temp);
+
+ if (temp > colibri_t20_shutdown_temp) {
+ /* First check for hardware over-temperature condition mandating
+ immediate shutdown */
+ pr_err("over-temperature condition %d degC reached, initiating "
+ "immediate shutdown", temp);
+ kernel_power_off();
+ } else if (temp < colibri_t20_throttle_temp -
+ colibri_t20_throttle_hysteresis) {
+ /* Make sure throttling gets disabled again */
+ if (tegra_is_throttling()) {
+ tegra_throttling_enable(false);
+ lm95245_set_remote_os_limit(lm95245_device,
+ colibri_t20_throttle_temp);
+ }
+ } else if (temp < colibri_t20_throttle_temp) {
+ /* Operating within hysteresis so keep re-scheduling to catch
+ leaving below throttle again */
+ if (tegra_is_throttling()) {
+ msleep(100);
+ queue_work(thermd_alert_workqueue, &thermd_alert_work);
+ }
+ } else if (temp >= colibri_t20_throttle_temp) {
+ /* Make sure throttling gets enabled and set shutdown limit */
+ if (!tegra_is_throttling()) {
+ tegra_throttling_enable(true);
+ lm95245_set_remote_os_limit(lm95245_device,
+ colibri_t20_shutdown_temp);
+ }
+ /* And re-schedule again */
+ msleep(100);
+ queue_work(thermd_alert_workqueue, &thermd_alert_work);
+ }
+
+ /* Avoid unbalanced enable for IRQ 367 */
+ if (thermd_alert_irq_disabled) {
+ thermd_alert_irq_disabled = 0;
+ enable_irq(gpio_to_irq(THERMD_ALERT));
+ }
+}
+
+static void colibri_t20_thermd_alert_init(void)
+{
+ gpio_request(THERMD_ALERT, "THERMD_ALERT");
+ gpio_direction_input(THERMD_ALERT);
+
+ thermd_alert_workqueue = create_singlethread_workqueue("THERMD_ALERT");
+
+ INIT_WORK(&thermd_alert_work, thermd_alert_work_func);
+}
+
+static void lm95245_probe_callback(struct device *dev)
+{
+ lm95245_device = dev;
+
+ lm95245_set_remote_os_limit(lm95245_device, colibri_t20_throttle_temp);
+
+ if (request_irq(gpio_to_irq(THERMD_ALERT), thermd_alert_irq,
+ IRQF_TRIGGER_LOW, "THERMD_ALERT", NULL))
+ pr_err("%s: unable to register THERMD_ALERT interrupt\n",
+ __func__);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int colibri_t20_thermal_get_throttle_temp(void *data, u64 *val)
+{
+ *val = (u64)colibri_t20_throttle_temp;
+ return 0;
+}
+
+static int colibri_t20_thermal_set_throttle_temp(void *data, u64 val)
+{
+ colibri_t20_throttle_temp = val;
+ if (!tegra_is_throttling() && lm95245_device)
+ lm95245_set_remote_os_limit(lm95245_device,
+ colibri_t20_throttle_temp);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(throttle_fops,
+ colibri_t20_thermal_get_throttle_temp,
+ colibri_t20_thermal_set_throttle_temp,
+ "%llu\n");
+
+static int colibri_t20_thermal_get_shutdown_temp(void *data, u64 *val)
+{
+ *val = (u64)colibri_t20_shutdown_temp;
+ return 0;
+}
+
+static int colibri_t20_thermal_set_shutdown_temp(void *data, u64 val)
+{
+ colibri_t20_shutdown_temp = val;
+ if (tegra_is_throttling() && lm95245_device)
+ lm95245_set_remote_os_limit(lm95245_device,
+ colibri_t20_shutdown_temp);
+
+ /* Carefull as we can only actively monitor one temperatur limit and
+ assumption is throttling is lower than shutdown one. */
+ if (colibri_t20_shutdown_temp < colibri_t20_throttle_temp)
+ colibri_t20_thermal_set_throttle_temp(NULL,
+ colibri_t20_shutdown_temp);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(shutdown_fops,
+ colibri_t20_thermal_get_shutdown_temp,
+ colibri_t20_thermal_set_shutdown_temp,
+ "%llu\n");
+
+static int __init colibri_t20_thermal_debug_init(void)
+{
+ struct dentry *thermal_debugfs_root;
+
+ thermal_debugfs_root = debugfs_create_dir("thermal", 0);
+
+ if (!debugfs_create_file("throttle", 0644, thermal_debugfs_root,
+ NULL, &throttle_fops))
+ return -ENOMEM;
+
+ if (!debugfs_create_file("shutdown", 0644, thermal_debugfs_root,
+ NULL, &shutdown_fops))
+ return -ENOMEM;
+
+ return 0;
+}
+late_initcall(colibri_t20_thermal_debug_init);
+#endif /* CONFIG_DEBUG_FS */
+
+/* UART */
+
+static struct platform_device *colibri_t20_uart_devices[] __initdata = {
+ &tegra_uarta_device, /* Colibri FFUART */
+#ifndef GMI_32BIT
+ &tegra_uartd_device, /* Colibri BTUART */
+#endif
+ &tegra_uartb_device, /* Colibri STDUART */
+};
+
+static struct uart_clk_parent uart_parent_clk[] = {
+ [0] = {.name = "pll_p"},
+ [1] = {.name = "pll_m"},
+ [2] = {.name = "clk_m"},
+};
+
+static struct tegra_uart_platform_data colibri_t20_uart_pdata;
+
+static void __init uart_debug_init(void)
+{
+ unsigned long rate;
+ struct clk *c;
+
+ /* UARTA is the debug port. */
+ pr_info("Selecting UARTA as the debug console\n");
+ colibri_t20_uart_devices[0] = &debug_uarta_device;
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uarta_device.dev.platform_data))->mapbase;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uarta");
+
+ /* Clock enable for the debug channel */
+ if (!IS_ERR_OR_NULL(debug_uart_clk)) {
+ rate = ((struct plat_serial8250_port *)(
+ debug_uarta_device.dev.platform_data))->uartclk;
+ pr_info("The debug console clock name is %s\n",
+ debug_uart_clk->name);
+ c = tegra_get_clock_by_name("pll_p");
+ if (IS_ERR_OR_NULL(c))
+ pr_err("Not getting the parent clock pll_p\n");
+ else
+ clk_set_parent(debug_uart_clk, c);
+
+ clk_enable(debug_uart_clk);
+ clk_set_rate(debug_uart_clk, rate);
+ } else {
+ pr_err("Not getting the clock %s for debug console\n",
+ debug_uart_clk->name);
+ }
+}
+
+static void __init colibri_t20_uart_init(void)
+{
+ int i;
+ struct clk *c;
+
+ for (i = 0; i < ARRAY_SIZE(uart_parent_clk); ++i) {
+ c = tegra_get_clock_by_name(uart_parent_clk[i].name);
+ if (IS_ERR_OR_NULL(c)) {
+ pr_err("Not able to get the clock for %s\n",
+ uart_parent_clk[i].name);
+ continue;
+ }
+ uart_parent_clk[i].parent_clk = c;
+ uart_parent_clk[i].fixed_clk_rate = clk_get_rate(c);
+ }
+ colibri_t20_uart_pdata.parent_clk_list = uart_parent_clk;
+ colibri_t20_uart_pdata.parent_clk_count = ARRAY_SIZE(uart_parent_clk);
+ tegra_uarta_device.dev.platform_data = &colibri_t20_uart_pdata;
+ tegra_uartb_device.dev.platform_data = &colibri_t20_uart_pdata;
+#ifndef GMI_32BIT
+ tegra_uartd_device.dev.platform_data = &colibri_t20_uart_pdata;
+#endif
+
+ /* Register low speed only if it is selected */
+ if (!is_tegra_debug_uartport_hs())
+ uart_debug_init();
+
+ platform_add_devices(colibri_t20_uart_devices,
+ ARRAY_SIZE(colibri_t20_uart_devices));
+}
+
+/* USB */
+
+//TODO: overcurrent
+
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .has_hostpc = false,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = true,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 8,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+ .u_data.dev = {
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
+ .vbus_gpio = -1,
+ .vbus_pmu_irq = 0,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .has_hostpc = false,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = true,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 9,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 8,
+ },
+ .u_data.host = {
+ .hot_plug = true,
+ .power_off_on_suspend = false,
+ .remote_wakeup_supported = false,
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ },
+};
+
+static void ulpi_link_platform_open(void)
+{
+ int reset_gpio = USB3340_RESETB;
+
+ gpio_request(reset_gpio, "ulpi_phy_reset");
+ gpio_direction_output(reset_gpio, 0);
+ msleep(5);
+ gpio_direction_output(reset_gpio, 1);
+}
+
+static void ulpi_link_platform_post_phy_on(void)
+{
+ /* enable VBUS */
+ gpio_set_value(LAN_V_BUS, 1);
+
+ /* reset */
+ gpio_set_value(LAN_RESET, 0);
+
+ udelay(5);
+
+ /* unreset */
+ gpio_set_value(LAN_RESET, 1);
+}
+
+static void ulpi_link_platform_pre_phy_off(void)
+{
+ /* disable VBUS */
+ gpio_set_value(LAN_V_BUS, 0);
+}
+
+static struct tegra_usb_phy_platform_ops ulpi_link_plat_ops = {
+ .open = ulpi_link_platform_open,
+ .post_phy_on = ulpi_link_platform_post_phy_on,
+ .pre_phy_off = ulpi_link_platform_pre_phy_off,
+};
+
+static struct tegra_usb_platform_data tegra_ehci2_ulpi_link_pdata = {
+ .has_hostpc = false,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .ops = &ulpi_link_plat_ops,
+ .phy_intf = TEGRA_USB_PHY_INTF_ULPI_LINK,
+ .port_otg = false,
+ .u_cfg.ulpi = {
+ .clk = "cdev2",
+ .clock_out_delay = 1,
+ .data_trimmer = 4,
+ .dir_trimmer = 4,
+ .shadow_clk_delay = 10,
+ .stpdirnxt_trimmer = 4,
+ },
+ .u_data.host = {
+ .hot_plug = false,
+ .power_off_on_suspend = true,
+ .remote_wakeup_supported = false,
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
+ .has_hostpc = false,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = false,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 9,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 8,
+ },
+ .u_data.host = {
+ .hot_plug = true,
+ .power_off_on_suspend = false,
+ .remote_wakeup_supported = false,
+#ifdef MECS_TELLURIUM_XPOD2
+ .vbus_gpio = -1,
+#else
+ .vbus_gpio = USBH_PEN,
+ .vbus_gpio_inverted = 1,
+#endif
+ .vbus_reg = NULL,
+ },
+};
+
+#ifndef CONFIG_USB_TEGRA_OTG
+static struct platform_device *tegra_usb_otg_host_register(void)
+{
+ struct platform_device *pdev;
+ void *platform_data;
+ int val;
+
+ pdev = platform_device_alloc(tegra_ehci1_device.name,
+ tegra_ehci1_device.id);
+ if (!pdev)
+ return NULL;
+
+ val = platform_device_add_resources(pdev, tegra_ehci1_device.resource,
+ tegra_ehci1_device.num_resources);
+ if (val)
+ goto error;
+
+ pdev->dev.dma_mask = tegra_ehci1_device.dev.dma_mask;
+ pdev->dev.coherent_dma_mask = tegra_ehci1_device.dev.coherent_dma_mask;
+
+ platform_data = kmalloc(sizeof(struct tegra_usb_platform_data),
+ GFP_KERNEL);
+ if (!platform_data)
+ goto error;
+
+ memcpy(platform_data, &tegra_ehci1_utmi_pdata,
+ sizeof(struct tegra_usb_platform_data));
+ pdev->dev.platform_data = platform_data;
+
+ val = platform_device_add(pdev);
+ if (val)
+ goto error_add;
+
+ return pdev;
+
+error_add:
+ kfree(platform_data);
+error:
+ pr_err("%s: failed to add the host controller device\n", __func__);
+ platform_device_put(pdev);
+ return NULL;
+}
+
+static void tegra_usb_otg_host_unregister(struct platform_device *pdev)
+{
+ platform_device_unregister(pdev);
+}
+
+static struct colibri_otg_platform_data colibri_otg_pdata = {
+ .cable_detect_gpio = USBC_DET,
+ .host_register = &tegra_usb_otg_host_register,
+ .host_unregister = &tegra_usb_otg_host_unregister,
+};
+#else /* !CONFIG_USB_TEGRA_OTG */
+static struct tegra_usb_otg_data tegra_otg_pdata = {
+ .ehci_device = &tegra_ehci1_device,
+ .ehci_pdata = &tegra_ehci1_utmi_pdata,
+};
+#endif /* !CONFIG_USB_TEGRA_OTG */
+
+#ifndef CONFIG_USB_TEGRA_OTG
+struct platform_device colibri_otg_device = {
+ .name = "colibri-otg",
+ .id = -1,
+ .dev = {
+ .platform_data = &colibri_otg_pdata,
+ },
+};
+#endif /* !CONFIG_USB_TEGRA_OTG */
+
+static void colibri_t20_usb_init(void)
+{
+ gpio_request(LAN_V_BUS, "LAN_V_BUS");
+ gpio_direction_output(LAN_V_BUS, 0);
+ gpio_export(LAN_V_BUS, false);
+
+ gpio_request(LAN_RESET, "LAN_RESET");
+ gpio_direction_output(LAN_RESET, 0);
+ gpio_export(LAN_RESET, false);
+
+ /* OTG should be the first to be registered
+ EHCI instance 0: USB1_DP/N -> USBOTG_P/N */
+#ifndef CONFIG_USB_TEGRA_OTG
+ platform_device_register(&colibri_otg_device);
+#else /* !CONFIG_USB_TEGRA_OTG */
+ tegra_otg_device.dev.platform_data = &tegra_otg_pdata;
+ platform_device_register(&tegra_otg_device);
+#endif /* !CONFIG_USB_TEGRA_OTG */
+
+ /* setup the udc platform data */
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
+ platform_device_register(&tegra_udc_device);
+
+ /* EHCI instance 1: ULPI PHY -> ASIX ETH */
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_ulpi_link_pdata;
+ platform_device_register(&tegra_ehci2_device);
+
+ /* EHCI instance 2: USB3_DP/N -> USBH1_P/N */
+ tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata;
+ platform_device_register(&tegra_ehci3_device);
+
+#ifdef MECS_TELLURIUM
+//SD card multiplexing: pull GPIO_PT2 and GPIO_PBB2 low
+//working even without any modifications
+ {
+ int gpio_status;
+ unsigned int i2c_scl = I2C_SCL;
+ unsigned int i2c_sda = I2C_SDA;
+ unsigned int tellurium_usb_hub_reset = MECS_USB_HUB_RESET;
+
+ printk("MECS Tellurium USB Hub Initialisation\n");
+
+ /* configure USB hub reset line as output and pull low into
+ reset */
+ gpio_status = gpio_request(tellurium_usb_hub_reset,
+ "USB_HUB_RESET");
+ if (gpio_status < 0)
+ pr_warning("USB_HUB_RESET request GPIO FAILED\n");
+ gpio_status = gpio_direction_output(tellurium_usb_hub_reset,
+ 0);
+ if (gpio_status < 0)
+ pr_warning("USB_HUB_RESET request GPIO DIRECTION "
+ "FAILED\n");
+
+ /* configure I2C pins as outputs and pull low */
+ gpio_status = gpio_direction_output(i2c_scl, 0);
+ if (gpio_status < 0)
+ pr_warning("I2C_SCL request GPIO DIRECTION FAILED\n");
+ gpio_status = gpio_direction_output(i2c_sda, 0);
+ if (gpio_status < 0)
+ pr_warning("I2C_SDA request GPIO DIRECTION FAILED\n");
+
+ /* pull USB hub out of reset */
+ gpio_set_value(tellurium_usb_hub_reset, 1);
+
+ /* release I2C pins again */
+ tegra_gpio_disable(i2c_scl);
+ tegra_gpio_disable(i2c_sda);
+ }
+#endif /* MECS_TELLURIUM */
+}
+
+/* W1, aka OWR, aka OneWire */
+
+#ifdef CONFIG_W1_MASTER_TEGRA
+struct tegra_w1_timings colibri_t20_w1_timings = {
+ .tsu = 1,
+ .trelease = 0xf,
+ .trdv = 0xf,
+ .tlow0 = 0x3c,
+ .tlow1 = 1,
+ .tslot = 0x77,
+
+ .tpdl = 0x78,
+ .tpdh = 0x1e,
+ .trstl = 0x1df,
+ .trsth = 0x1df,
+ .rdsclk = 0x7,
+ .psclk = 0x50,
+};
+
+struct tegra_w1_platform_data colibri_t20_w1_platform_data = {
+ .clk_id = "tegra_w1",
+ .timings = &colibri_t20_w1_timings,
+};
+#endif /* CONFIG_W1_MASTER_TEGRA */
+
+static struct platform_device *colibri_t20_devices[] __initdata = {
+#ifdef CONFIG_RTC_DRV_TEGRA
+ &tegra_rtc_device,
+#endif
+ &tegra_nand_device,
+
+ &tegra_pmu_device,
+ &tegra_gart_device,
+ &tegra_aes_device,
+#ifdef CONFIG_KEYBOARD_GPIO
+ &colibri_t20_keys_device,
+#endif
+ &tegra_wdt_device,
+ &tegra_avp_device,
+#ifdef CONFIG_TEGRA_CAMERA
+ &tegra_camera,
+#endif
+ &tegra_ac97_device,
+ &tegra_spdif_device,
+ &tegra_das_device,
+ &spdif_dit_device,
+//bluetooth
+ &tegra_pcm_device,
+ &colibri_t20_audio_device,
+ &tegra_spi_device4,
+#ifdef MECS_TELLURIUM_XPOD2
+ &xpod2_spi_device,
+#endif
+ &tegra_led_pwm_device,
+ &tegra_pwfm1_device,
+#ifndef MECS_TELLURIUM
+ &tegra_pwfm2_device,
+#else
+ &tegra_pwfm0_device,
+#endif
+ &tegra_pwfm3_device,
+#ifdef CONFIG_W1_MASTER_TEGRA
+ &tegra_w1_device,
+#endif
+};
+
+static void __init colibri_t20_init(void)
+{
+ tegra_clk_init_from_table(colibri_t20_clk_init_table);
+ colibri_t20_pinmux_init();
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+ writel(TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG);
+ writel(TEGRA_SNOR_CONFIG_GO | TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG);
+ colibri_can_resource[1].start = gpio_to_irq(TEGRA_GPIO_PA0);
+ colibri_can_resource[1].end = gpio_to_irq(TEGRA_GPIO_PA0);
+ platform_device_register(&colibri_can_device);
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
+ colibri_t20_thermd_alert_init();
+ colibri_t20_i2c_init();
+ colibri_t20_uart_init();
+//
+ tegra_ac97_device.dev.platform_data = &colibri_t20_wm97xx_pdata;
+//
+#ifdef CONFIG_W1_MASTER_TEGRA
+ tegra_w1_device.dev.platform_data = &colibri_t20_w1_platform_data;
+#endif
+ platform_add_devices(colibri_t20_devices,
+ ARRAY_SIZE(colibri_t20_devices));
+ tegra_ram_console_debug_init();
+#ifndef GMI_32BIT
+ colibri_t20_sdhci_init();
+#endif
+ colibri_t20_regulator_init();
+
+// tegra_das_device.dev.platform_data = &tegra_das_pdata;
+// tegra_ac97_device.dev.platform_data = &tegra_audio_pdata;
+// tegra_spdif_input_device.name = "spdif";
+// tegra_spdif_input_device.dev.platform_data = &tegra_spdif_audio_pdata;
+
+ colibri_t20_usb_init();
+ colibri_t20_panel_init();
+//sensors
+
+ /* Note: V1.1c modules require proper BCT setting 666 rather than
+ 721.5 MHz EMC clock */
+ colibri_t20_emc_init();
+
+ colibri_t20_gpio_init();
+ colibri_t20_register_spidev();
+ colibri_t20_mcp2515_can_init();
+
+#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE)
+ t20_get_tegra_vi01_device()->dev.platform_data = &tegra_camera_platform_data;
+#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE)
+ platform_device_register(&soc_camera_max9526);
+#endif
+#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE)
+ platform_device_register(&soc_camera_adv7180);
+#endif
+
+#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */
+
+ tegra_release_bootloader_fb();
+}
+
+int __init tegra_colibri_t20_protected_aperture_init(void)
+{
+ if (!machine_is_colibri_t20())
+ return 0;
+
+ tegra_protected_aperture_init(tegra_grhost_aperture);
+ return 0;
+}
+late_initcall(tegra_colibri_t20_protected_aperture_init);
+
+void __init colibri_t20_reserve(void)
+{
+ if (memblock_reserve(0x0, 4096) < 0)
+ pr_warn("Cannot reserve first 4K of memory for safety\n");
+
+ /* we specify zero for special handling due to already reserved
+ fbmem/nvmem (U-Boot 2011.06 compatibility from our V1.x images) */
+ tegra_reserve(0, SZ_8M + SZ_1M, SZ_16M);
+ tegra_ram_console_debug_reserve(SZ_1M);
+}
+
+static const char *colibri_t20_dt_board_compat[] = {
+ "toradex,colibri_t20",
+ NULL
+};
+
+#ifdef CONFIG_ANDROID
+MACHINE_START(COLIBRI_T20, "ventana")
+#else
+MACHINE_START(COLIBRI_T20, "Toradex Colibri T20")
+#endif
+ .boot_params = 0x00000100,
+ .dt_compat = colibri_t20_dt_board_compat,
+ .init_early = tegra_init_early,
+ .init_irq = tegra_init_irq,
+ .init_machine = colibri_t20_init,
+ .map_io = tegra_map_common_io,
+ .reserve = colibri_t20_reserve,
+ .timer = &tegra_timer,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/board-colibri_t20.h b/arch/arm/mach-tegra/board-colibri_t20.h
new file mode 100644
index 000000000000..020670d424fd
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t20.h
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t20.h
+ *
+ * Copyright (C) 2011 Toradex, 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.
+ *
+ */
+
+#ifndef _MACH_TEGRA_BOARD_COLIBRI_T20_H
+#define _MACH_TEGRA_BOARD_COLIBRI_T20_H
+
+/* Uncomment for camera interface support on Colibri Evaluation carrier
+ board */
+#if defined(CONFIG_TEGRA_CAMERA) || defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE)
+#define COLIBRI_T20_VI
+#endif
+
+/* Uncomment to activate 32-bit GMI address/databus */
+//#define GMI_32BIT
+
+/* GPIO */
+
+#define FF_DCD TEGRA_GPIO_PC6 /* SODIMM 31 */
+#define FF_DSR TEGRA_GPIO_PC1 /* SODIMM 29 */
+
+#define I2C_SCL TEGRA_GPIO_PC4 /* SODIMM 196 */
+#define I2C_SDA TEGRA_GPIO_PC5 /* SODIMM 194 */
+
+#define LAN_EXT_WAKEUP TEGRA GPIO_PV5
+#define LAN_PME TEGRA_GPIO_PV6
+#define LAN_RESET TEGRA_GPIO_PV4
+#define LAN_V_BUS TEGRA_GPIO_PBB1
+
+#define MECS_USB_HUB_RESET TEGRA_GPIO_PBB3 /* SODIMM 127 */
+
+#define MMC_CD TEGRA_GPIO_PC7 /* SODIMM 43 */
+
+#define NAND_WP_N TEGRA_GPIO_PS0
+
+#define PWR_I2C_SCL TEGRA_GPIO_PZ6
+#define PWR_I2C_SDA TEGRA_GPIO_PZ7
+
+#define THERMD_ALERT TEGRA_GPIO_PV7
+
+#define TOUCH_PEN_INT TEGRA_GPIO_PV2
+
+#define USB3340_RESETB TEGRA_GPIO_PV1
+//conflicts with MECS Tellurium xPOD2 SSPTXD2
+#define USBC_DET TEGRA_GPIO_PK5 /* SODIMM 137 */
+#define USBH_OC TEGRA_GPIO_PW3 /* SODIMM 131 */
+#define USBH_PEN TEGRA_GPIO_PW2 /* SODIMM 129 */
+
+/* Use SODIMM pin 73 as DAC power save on Iris carrier board */
+#define IRIS
+
+/* Uncomment for back light and USB hub support on MECS Tellurium carrier
+ board */
+//#define MECS_TELLURIUM
+
+/* Uncomment to use the xPOD2 which due to its Colibri T20 incompatible wiring
+ uses GPIO bit banging SPI driver rather than a hardware SPI controller */
+//#define MECS_TELLURIUM_XPOD2
+
+/* Uncomment for 8-bit SDHCI on HSMMC controller (requires custom carrier
+ board) */
+//#define SDHCI_8BIT
+
+/* TPS6586X gpios */
+#define TPS6586X_GPIO_BASE TEGRA_NR_GPIOS
+
+/* Interrupt numbers from external peripherals */
+#define TPS6586X_INT_BASE TEGRA_NR_IRQS
+#define TPS6586X_INT_END (TPS6586X_INT_BASE + 32)
+
+int colibri_t20_emc_init(void);
+int colibri_t20_panel_init(void);
+int colibri_t20_pinmux_init(void);
+int colibri_t20_regulator_init(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/board-colibri_t30-memory.c b/arch/arm/mach-tegra/board-colibri_t30-memory.c
new file mode 100644
index 000000000000..22575b48ba0c
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t30-memory.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2012 Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "board.h"
+#include "board-colibri_t30.h"
+#include "tegra3_emc.h"
+#include "fuse.h"
+
+static const struct tegra_emc_table colibri_t30_emc_tables_nt5cc256m16cp[] = {
+ {
+ 0x32, /* Rev 3.2 */
+ 400000, /* SDRAM frequency */
+ {
+ 0x00000012, /* EMC_RC */
+ 0x0000008a, /* EMC_RFC */
+ 0x0000000c, /* EMC_RAS */
+ 0x00000004, /* EMC_RP */
+ 0x00000003, /* EMC_R2W */
+ 0x00000008, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x0000000a, /* EMC_W2P */
+ 0x00000004, /* EMC_RD_RCD */
+ 0x00000004, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000004, /* EMC_WDV */
+ 0x00000006, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x00000009, /* EMC_QSAFE */
+ 0x0000000c, /* EMC_RDV */
+ 0x00000bf5, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000002fd, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000008, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000008, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x00000090, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x00000010, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x00000c35, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00007088, /* EMC_FBIO_CFG5 */
+ 0x00360084, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x0000c002, /* EMC_DLL_XFORM_DQS0 */
+ 0x00014002, /* EMC_DLL_XFORM_DQS1 */
+ 0x0000c002, /* EMC_DLL_XFORM_DQS2 */
+ 0x00014002, /* EMC_DLL_XFORM_DQS3 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00014000, /* EMC_DLL_XFORM_DQS7 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000000, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00018000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00018000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00018000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00018000, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0a00013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f508, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x08000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x0134000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800018d1, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
+ 0x80000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000009, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000007, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06030202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000d0709, /* MC_EMEM_ARB_DA_COVERS */
+ 0x7086120a, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff88, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000521, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200000, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 800000, /* SDRAM frequency */
+ {
+ 0x00000025, /* EMC_RC */
+ 0x00000116, /* EMC_RFC */
+ 0x0000001a, /* EMC_RAS */
+ 0x00000009, /* EMC_RP */
+ 0x00000005, /* EMC_R2W */
+ 0x0000000d, /* EMC_W2R */
+ 0x00000004, /* EMC_R2P */
+ 0x00000013, /* EMC_W2P */
+ 0x00000009, /* EMC_RD_RCD */
+ 0x00000009, /* EMC_WR_RCD */
+ 0x00000006, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000007, /* EMC_WDV */
+ 0x0000000a, /* EMC_QUSE */
+ 0x00000009, /* EMC_QRST */
+ 0x0000000b, /* EMC_QSAFE */
+ 0x00000011, /* EMC_RDV */
+ 0x0000182a, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x0000060a, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000003, /* EMC_PDEX2WR */
+ 0x00000012, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000f, /* EMC_AR2PDEN */
+ 0x00000018, /* EMC_RW2PDEN */
+ 0x00000120, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000005, /* EMC_TCKE */
+ 0x00000020, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000007, /* EMC_TCLKSTABLE */
+ 0x00000008, /* EMC_TCLKSTOP */
+ 0x0000186a, /* EMC_TREFBW */
+ 0x0000000b, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0xf01a0191, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x007fc00c, /* EMC_DLL_XFORM_DQS0 */
+ 0x0000400c, /* EMC_DLL_XFORM_DQS1 */
+ 0x007f800c, /* EMC_DLL_XFORM_DQS2 */
+ 0x0000400c, /* EMC_DLL_XFORM_DQS3 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQS4 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQS5 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQS6 */
+ 0x0000000c, /* EMC_DLL_XFORM_DQS7 */
+ 0x00018000, /* EMC_DLL_XFORM_QUSE0 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE1 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE2 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE3 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE4 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE5 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE6 */
+ 0x00000000, /* EMC_DLL_XFORM_QUSE7 */
+ 0x00000002, /* EMC_DLI_TRIM_TXDQS0 */
+ 0x00000002, /* EMC_DLI_TRIM_TXDQS1 */
+ 0x00000002, /* EMC_DLI_TRIM_TXDQS2 */
+ 0x00000002, /* EMC_DLI_TRIM_TXDQS3 */
+ 0x00000002, /* EMC_DLI_TRIM_TXDQS4 */
+ 0x00000002, /* EMC_DLI_TRIM_TXDQS5 */
+ 0x00000002, /* EMC_DLI_TRIM_TXDQS6 */
+ 0x00000002, /* EMC_DLI_TRIM_TXDQS7 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ3 */
+ 0x000602a0, /* EMC_XM2CMDPADCTRL */
+ 0x0a00013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x22220000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f501, /* EMC_XM2COMPPADCTRL */
+ 0x07077404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000000, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x080001e8, /* EMC_XM2QUSEPADCTRL */
+ 0x08000021, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00020000, /* EMC_ZCAL_INTERVAL */
+ 0x00000100, /* EMC_ZCAL_WAIT_CNT */
+ 0x00a8000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000309f, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000c, /* MC_EMEM_ARB_CFG */
+ 0x80000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000005, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000013, /* MC_EMEM_ARB_TIMING_RC */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x0000000f, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000c, /* MC_EMEM_ARB_TIMING_WAP2PRE */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2R */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000008, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x08040202, /* MC_EMEM_ARB_DA_TURNS */
+ 0x00160d13, /* MC_EMEM_ARB_DA_COVERS */
+ 0x712c2414, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xf8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff49, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x80000d71, /* Mode Register 0 */
+ 0x80100002, /* Mode Register 1 */
+ 0x80200018, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+};
+
+int colibri_t30_emc_init(void)
+{
+ tegra_init_emc(colibri_t30_emc_tables_nt5cc256m16cp,
+ ARRAY_SIZE(colibri_t30_emc_tables_nt5cc256m16cp));
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/board-colibri_t30-panel.c b/arch/arm/mach-tegra/board-colibri_t30-panel.c
new file mode 100644
index 000000000000..14c711039f41
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t30-panel.c
@@ -0,0 +1,529 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t30-panel.c
+ *
+ * Copyright (c) 2012, Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <asm/atomic.h>
+#include <asm/mach-types.h>
+
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/gpio.h>
+#include <linux/ion.h>
+#include <linux/nvhost.h>
+#include <linux/nvmap.h>
+#include <linux/platform_device.h>
+#include <linux/pwm_backlight.h>
+#include <linux/regulator/consumer.h>
+#include <linux/resource.h>
+#include <linux/tegra_ion.h>
+
+#include <mach/dc.h>
+#include <mach/fb.h>
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+#include <mach/smmu.h>
+
+#include "board.h"
+#include "board-colibri_t30.h"
+#include "devices.h"
+#include "gpio-names.h"
+#include "tegra3_host1x_devices.h"
+
+#ifndef COLIBRI_T30_VI
+#define colibri_t30_bl_enb TEGRA_GPIO_PV2 /* BL_ON */
+#endif
+#define colibri_t30_hdmi_hpd TEGRA_GPIO_PN7 /* HDMI_INT_N */
+
+static struct regulator *colibri_t30_hdmi_pll = NULL;
+static struct regulator *colibri_t30_hdmi_reg = NULL;
+
+#ifndef COLIBRI_T30_VI
+static int colibri_t30_backlight_init(struct device *dev) {
+ int ret;
+
+ ret = gpio_request(colibri_t30_bl_enb, "BL_ON");
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_direction_output(colibri_t30_bl_enb, 1);
+ if (ret < 0)
+ gpio_free(colibri_t30_bl_enb);
+
+ return ret;
+};
+
+static void colibri_t30_backlight_exit(struct device *dev) {
+ gpio_set_value(colibri_t30_bl_enb, 0);
+ gpio_free(colibri_t30_bl_enb);
+}
+
+static int colibri_t30_backlight_notify(struct device *dev, int brightness)
+{
+ struct platform_pwm_backlight_data *pdata = dev->platform_data;
+
+ gpio_set_value(colibri_t30_bl_enb, !!brightness);
+
+ /* Unified TFT interface displays (e.g. EDT ET070080DH6) LEDCTRL pin
+ with inverted behaviour (e.g. 0V brightest vs. 3.3V darkest)
+ Note: brightness polarity display model specific */
+ if (brightness) return pdata->max_brightness - brightness;
+ else return brightness;
+}
+
+static int colibri_t30_disp1_check_fb(struct device *dev, struct fb_info *info);
+
+static struct platform_pwm_backlight_data colibri_t30_backlight_data = {
+ .pwm_id = 0,
+ .max_brightness = 255,
+ .dft_brightness = 127,
+ .pwm_period_ns = 1000000, /* 1 kHz */
+ .init = colibri_t30_backlight_init,
+ .exit = colibri_t30_backlight_exit,
+ .notify = colibri_t30_backlight_notify,
+ /* Only toggle backlight on fb blank notifications for disp1 */
+ .check_fb = colibri_t30_disp1_check_fb,
+};
+
+static struct platform_device colibri_t30_backlight_device = {
+ .name = "pwm-backlight",
+ .id = -1,
+ .dev = {
+ .platform_data = &colibri_t30_backlight_data,
+ },
+};
+#endif /* !COLIBRI_T30_VI */
+
+static int colibri_t30_panel_enable(void)
+{
+ return 0;
+}
+
+static int colibri_t30_panel_disable(void)
+{
+ return 0;
+}
+
+#ifdef CONFIG_TEGRA_DC
+
+static int colibri_t30_hdmi_enable(void)
+{
+ int ret;
+ if (!colibri_t30_hdmi_reg) {
+ colibri_t30_hdmi_reg = regulator_get(NULL, "avdd_hdmi");
+ if (IS_ERR_OR_NULL(colibri_t30_hdmi_reg)) {
+ pr_err("hdmi: couldn't get regulator avdd_hdmi\n");
+ colibri_t30_hdmi_reg = NULL;
+ return PTR_ERR(colibri_t30_hdmi_reg);
+ }
+ }
+ ret = regulator_enable(colibri_t30_hdmi_reg);
+ if (ret < 0) {
+ pr_err("hdmi: couldn't enable regulator avdd_hdmi\n");
+ return ret;
+ }
+ if (!colibri_t30_hdmi_pll) {
+ colibri_t30_hdmi_pll = regulator_get(NULL, "avdd_hdmi_pll");
+ if (IS_ERR_OR_NULL(colibri_t30_hdmi_pll)) {
+ pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n");
+ colibri_t30_hdmi_pll = NULL;
+ regulator_put(colibri_t30_hdmi_reg);
+ colibri_t30_hdmi_reg = NULL;
+ return PTR_ERR(colibri_t30_hdmi_pll);
+ }
+ }
+ ret = regulator_enable(colibri_t30_hdmi_pll);
+ if (ret < 0) {
+ pr_err("hdmi: couldn't enable regulator avdd_hdmi_pll\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int colibri_t30_hdmi_disable(void)
+{
+ regulator_disable(colibri_t30_hdmi_reg);
+ regulator_put(colibri_t30_hdmi_reg);
+ colibri_t30_hdmi_reg = NULL;
+
+ regulator_disable(colibri_t30_hdmi_pll);
+ regulator_put(colibri_t30_hdmi_pll);
+ colibri_t30_hdmi_pll = NULL;
+ return 0;
+}
+static struct resource colibri_t30_disp1_resources[] = {
+ {
+ .name = "irq",
+ .start = INT_DISPLAY_GENERAL,
+ .end = INT_DISPLAY_GENERAL,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "regs",
+ .start = TEGRA_DISPLAY_BASE,
+ .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fbmem",
+ .start = 0, /* Filled in by colibri_t30_panel_init() */
+ .end = 0, /* Filled in by colibri_t30_panel_init() */
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource colibri_t30_disp2_resources[] = {
+ {
+ .name = "irq",
+ .start = INT_DISPLAY_B_GENERAL,
+ .end = INT_DISPLAY_B_GENERAL,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "regs",
+ .start = TEGRA_DISPLAY2_BASE,
+ .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fbmem",
+ .flags = IORESOURCE_MEM,
+ .start = 0,
+ .end = 0,
+ },
+ {
+ .name = "hdmi_regs",
+ .start = TEGRA_HDMI_BASE,
+ .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct tegra_fb_data colibri_t30_fb_data = {
+ .win = 0,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+static struct tegra_fb_data colibri_t30_hdmi_fb_data = {
+ .win = 0,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+static struct tegra_dc_out_pin colibri_t30_dc_out_pins[] = {
+ {
+ .name = TEGRA_DC_OUT_PIN_H_SYNC,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+ {
+ .name = TEGRA_DC_OUT_PIN_V_SYNC,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+ {
+ .name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+};
+
+static struct tegra_dc_out colibri_t30_disp1_out = {
+ .type = TEGRA_DC_OUT_RGB,
+ .parent_clk = "pll_d_out0",
+ .parent_clk_backup = "pll_d2_out0",
+
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+ .depth = 18,
+ .dither = TEGRA_DC_ORDERED_DITHER,
+
+ /* Use 32-bit depth for android builds */
+#ifdef CONFIG_ANDROID
+ .default_mode = "640x480-32@60",
+#else /* CONFIG_ANDROID */
+ .default_mode = "640x480-16@60",
+#endif /* CONFIG_ANDROID */
+
+ .out_pins = colibri_t30_dc_out_pins,
+ .n_out_pins = ARRAY_SIZE(colibri_t30_dc_out_pins),
+
+ .enable = colibri_t30_panel_enable,
+ .disable = colibri_t30_panel_disable,
+};
+
+static struct tegra_dc_out colibri_t30_disp2_out = {
+ .type = TEGRA_DC_OUT_HDMI,
+ .flags = TEGRA_DC_OUT_HOTPLUG_HIGH,
+ .parent_clk = "pll_d2_out0",
+
+ .dcc_bus = 3,
+ .hotplug_gpio = colibri_t30_hdmi_hpd,
+
+ .max_pixclock = KHZ2PICOS(148500),
+
+ /* Use 32-bit depth and Full HD for android builds */
+#ifdef CONFIG_ANDROID
+ .default_mode = "1920x1080-32@60",
+#else /* CONFIG_ANDROID */
+ .default_mode = "640x480-16@60",
+#endif /* CONFIG_ANDROID */
+
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+
+ .enable = colibri_t30_hdmi_enable,
+ .disable = colibri_t30_hdmi_disable,
+};
+
+static struct tegra_dc_platform_data colibri_t30_disp1_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &colibri_t30_disp1_out,
+ .emc_clk_rate = 300000000,
+ .fb = &colibri_t30_fb_data,
+};
+
+static struct tegra_dc_platform_data colibri_t30_disp2_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &colibri_t30_disp2_out,
+ .fb = &colibri_t30_hdmi_fb_data,
+ .emc_clk_rate = 300000000,
+};
+
+static struct nvhost_device colibri_t30_disp1_device = {
+ .name = "tegradc",
+ .id = 0,
+ .resource = colibri_t30_disp1_resources,
+ .num_resources = ARRAY_SIZE(colibri_t30_disp1_resources),
+ .dev = {
+ .platform_data = &colibri_t30_disp1_pdata,
+ },
+};
+
+#ifndef COLIBRI_T30_VI
+static int colibri_t30_disp1_check_fb(struct device *dev, struct fb_info *info)
+{
+ return info->device == &colibri_t30_disp1_device.dev;
+}
+#endif /* !COLIBRI_T30_VI */
+
+static struct nvhost_device colibri_t30_disp2_device = {
+ .name = "tegradc",
+ .id = 1,
+ .resource = colibri_t30_disp2_resources,
+ .num_resources = ARRAY_SIZE(colibri_t30_disp2_resources),
+ .dev = {
+ .platform_data = &colibri_t30_disp2_pdata,
+ },
+};
+#else /* CONFIG_TEGRA_DC */
+static int colibri_t30_disp1_check_fb(struct device *dev, struct fb_info *info)
+{
+ return 0;
+}
+#endif /* CONFIG_TEGRA_DC */
+
+#if defined(CONFIG_TEGRA_NVMAP)
+static struct nvmap_platform_carveout colibri_t30_carveouts[] = {
+ [0] = NVMAP_HEAP_CARVEOUT_IRAM_INIT,
+ [1] = {
+ .name = "generic-0",
+ .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC,
+ .base = 0, /* Filled in by colibri_t30_panel_init() */
+ .size = 0, /* Filled in by colibri_t30_panel_init() */
+ .buddy_size = SZ_32K,
+ },
+};
+
+static struct nvmap_platform_data colibri_t30_nvmap_data = {
+ .carveouts = colibri_t30_carveouts,
+ .nr_carveouts = ARRAY_SIZE(colibri_t30_carveouts),
+};
+
+static struct platform_device colibri_t30_nvmap_device = {
+ .name = "tegra-nvmap",
+ .id = -1,
+ .dev = {
+ .platform_data = &colibri_t30_nvmap_data,
+ },
+};
+#endif /* CONFIG_TEGRA_NVMAP */
+
+#if defined(CONFIG_ION_TEGRA)
+static struct platform_device tegra_iommu_device = {
+ .name = "tegra_iommu_device",
+ .id = -1,
+ .dev = {
+ .platform_data = (void *)((1 << HWGRP_COUNT) - 1),
+ },
+};
+
+static struct ion_platform_data tegra_ion_data = {
+ .nr = 4,
+ .heaps = {
+ {
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .id = TEGRA_ION_HEAP_CARVEOUT,
+ .name = "carveout",
+ .base = 0,
+ .size = 0,
+ },
+ {
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .id = TEGRA_ION_HEAP_IRAM,
+ .name = "iram",
+ .base = TEGRA_IRAM_BASE + TEGRA_RESET_HANDLER_SIZE,
+ .size = TEGRA_IRAM_SIZE - TEGRA_RESET_HANDLER_SIZE,
+ },
+ {
+ .type = ION_HEAP_TYPE_CARVEOUT,
+ .id = TEGRA_ION_HEAP_VPR,
+ .name = "vpr",
+ .base = 0,
+ .size = 0,
+ },
+ {
+ .type = ION_HEAP_TYPE_IOMMU,
+ .id = TEGRA_ION_HEAP_IOMMU,
+ .name = "iommu",
+ .base = TEGRA_SMMU_BASE,
+ .size = TEGRA_SMMU_SIZE,
+ .priv = &tegra_iommu_device.dev,
+ },
+ },
+};
+
+static struct platform_device tegra_ion_device = {
+ .name = "ion-tegra",
+ .id = -1,
+ .dev = {
+ .platform_data = &tegra_ion_data,
+ },
+};
+#endif /* CONFIG_ION_TEGRA */
+
+static struct platform_device *colibri_t30_gfx_devices[] __initdata = {
+#if defined(CONFIG_TEGRA_NVMAP)
+ &colibri_t30_nvmap_device,
+#endif
+#if defined(CONFIG_ION_TEGRA)
+ &tegra_ion_device,
+#endif
+#ifndef COLIBRI_T30_VI
+ &tegra_pwfm0_device,
+ &colibri_t30_backlight_device,
+#endif /* !COLIBRI_T30_VI */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/* put early_suspend/late_resume handlers here for the display in order
+ * to keep the code out of the display driver, keeping it closer to upstream
+ */
+struct early_suspend colibri_t30_panel_early_suspender;
+
+static void colibri_t30_panel_early_suspend(struct early_suspend *h)
+{
+ /* power down LCD, add use a black screen for HDMI */
+ if (num_registered_fb > 0)
+ fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
+ if (num_registered_fb > 1)
+ fb_blank(registered_fb[1], FB_BLANK_NORMAL);
+}
+
+static void colibri_t30_panel_late_resume(struct early_suspend *h)
+{
+ unsigned i;
+ for (i = 0; i < num_registered_fb; i++)
+ fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
+}
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+int __init colibri_t30_panel_init(void)
+{
+ int err = 0;
+ struct resource *res;
+ void __iomem *to_io;
+
+ /* enable hdmi hotplug gpio for hotplug detection */
+ gpio_request(colibri_t30_hdmi_hpd, "hdmi_hpd");
+ gpio_direction_input(colibri_t30_hdmi_hpd);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ colibri_t30_panel_early_suspender.suspend = colibri_t30_panel_early_suspend;
+ colibri_t30_panel_early_suspender.resume = colibri_t30_panel_late_resume;
+ colibri_t30_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ register_early_suspend(&colibri_t30_panel_early_suspender);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+#ifdef CONFIG_TEGRA_NVMAP
+ colibri_t30_carveouts[1].base = tegra_carveout_start;
+ colibri_t30_carveouts[1].size = tegra_carveout_size;
+#endif /* CONFIG_TEGRA_NVMAP */
+
+#ifdef CONFIG_ION_TEGRA
+ tegra_ion_data.heaps[0].base = tegra_carveout_start;
+ tegra_ion_data.heaps[0].size = tegra_carveout_size;
+#endif /* CONFIG_ION_TEGRA */
+
+#ifdef CONFIG_TEGRA_GRHOST
+ err = tegra3_register_host1x_devices();
+ if (err)
+ return err;
+#endif /* CONFIG_TEGRA_GRHOST */
+
+ err = platform_add_devices(colibri_t30_gfx_devices,
+ ARRAY_SIZE(colibri_t30_gfx_devices));
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
+ res = nvhost_get_resource_byname(&colibri_t30_disp1_device,
+ IORESOURCE_MEM, "fbmem");
+ res->start = tegra_fb_start;
+ res->end = tegra_fb_start + tegra_fb_size - 1;
+
+ res = nvhost_get_resource_byname(&colibri_t30_disp2_device,
+ IORESOURCE_MEM, "fbmem");
+ res->start = tegra_fb2_start;
+ res->end = tegra_fb2_start + tegra_fb2_size - 1;
+#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */
+
+ /* Make sure LVDS framebuffer is cleared. */
+ to_io = ioremap(tegra_fb_start, tegra_fb_size);
+ if (to_io) {
+ memset(to_io, 0, tegra_fb_size);
+ iounmap(to_io);
+ } else pr_err("%s: Failed to map LVDS framebuffer\n", __func__);
+
+ /* Make sure HDMI framebuffer is cleared.
+ Note: this seems to fix a tegradc.1 initialisation race in case of
+ framebuffer console as well. */
+ to_io = ioremap(tegra_fb2_start, tegra_fb2_size);
+ if (to_io) {
+ memset(to_io, 0, tegra_fb2_size);
+ iounmap(to_io);
+ } else pr_err("%s: Failed to map HDMI framebuffer\n", __func__);
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
+ if (!err)
+ err = nvhost_device_register(&colibri_t30_disp1_device);
+
+ if (!err)
+ err = nvhost_device_register(&colibri_t30_disp2_device);
+#endif /* CONFIG_TEGRA_GRHOST & CONFIG_TEGRA_DC */
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_NVAVP)
+ if (!err)
+ err = nvhost_device_register(&nvavp_device);
+#endif
+ return err;
+}
diff --git a/arch/arm/mach-tegra/board-colibri_t30-pinmux.c b/arch/arm/mach-tegra/board-colibri_t30-pinmux.c
new file mode 100644
index 000000000000..f02060c3d535
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t30-pinmux.c
@@ -0,0 +1,658 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t30-pinmux.c
+ *
+ * Copyright (C) 2012 Toradex, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <mach/pinmux.h>
+
+#include "board-colibri_t30.h"
+#include "board.h"
+#include "gpio-names.h"
+
+#define DEFAULT_DRIVE(_name) \
+ { \
+ .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
+ .hsm = TEGRA_HSM_DISABLE, \
+ .schmitt = TEGRA_SCHMITT_ENABLE, \
+ .drive = TEGRA_DRIVE_DIV_1, \
+ .pull_down = TEGRA_PULL_31, \
+ .pull_up = TEGRA_PULL_31, \
+ .slew_rising = TEGRA_SLEW_SLOWEST, \
+ .slew_falling = TEGRA_SLEW_SLOWEST, \
+ }
+
+/* Setting the drive strength of pins
+ * hsm: Enable High speed mode (ENABLE/DISABLE)
+ * Schimit: Enable/disable schimit (ENABLE/DISABLE)
+ * drive: low power mode (DIV_1, DIV_2, DIV_4, DIV_8)
+ * pulldn_drive - drive down (falling edge) - Driver Output Pull-Down drive
+ * strength code. Value from 0 to 31.
+ * pullup_drive - drive up (rising edge) - Driver Output Pull-Up drive
+ * strength code. Value from 0 to 31.
+ * pulldn_slew - Driver Output Pull-Up slew control code - 2bit code
+ * code 11 is least slewing of signal. code 00 is highest
+ * slewing of the signal.
+ * Value - FASTEST, FAST, SLOW, SLOWEST
+ * pullup_slew - Driver Output Pull-Down slew control code -
+ * code 11 is least slewing of signal. code 00 is highest
+ * slewing of the signal.
+ * Value - FASTEST, FAST, SLOW, SLOWEST
+ */
+#define SET_DRIVE(_name, _hsm, _schmitt, _drive, _pulldn_drive, _pullup_drive, _pulldn_slew, _pullup_slew) \
+ { \
+ .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
+ .hsm = TEGRA_HSM_##_hsm, \
+ .schmitt = TEGRA_SCHMITT_##_schmitt, \
+ .drive = TEGRA_DRIVE_##_drive, \
+ .pull_down = TEGRA_PULL_##_pulldn_drive, \
+ .pull_up = TEGRA_PULL_##_pullup_drive, \
+ .slew_rising = TEGRA_SLEW_##_pulldn_slew, \
+ .slew_falling = TEGRA_SLEW_##_pullup_slew, \
+ }
+
+static __initdata struct tegra_drive_pingroup_config colibri_t30_drive_pinmux[] = {
+ /* DEFAULT_DRIVE(<pin_group>), */
+
+ /* Audio codec */
+ SET_DRIVE(DAP2, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* All I2C pins are driven to maximum drive strength */
+
+ /* GEN1_I2C: I2C_SDA/SCL on SODIMM pin 194/196 (e.g. RTC on carrier board) */
+ SET_DRIVE(DBG, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* DDC_CLOCK/DATA on X3 pin 15/16 (e.g. display EDID) */
+ SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and
+ touch screen controller */
+ SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* SDMMC2 */
+ SET_DRIVE(AO2, DISABLE, DISABLE, DIV_1, 46, 42, FAST, FAST),
+
+ /* eMMC on SDMMC4 */
+ SET_DRIVE(GMA, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST),
+ SET_DRIVE(GMB, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST),
+ SET_DRIVE(GMC, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST),
+ SET_DRIVE(GMD, DISABLE, DISABLE, DIV_1, 9, 9, SLOWEST, SLOWEST),
+};
+
+#define DEFAULT_PINMUX(_pingroup, _mux, _pupd, _tri, _io) \
+ { \
+ .pingroup = TEGRA_PINGROUP_##_pingroup, \
+ .func = TEGRA_MUX_##_mux, \
+ .pupd = TEGRA_PUPD_##_pupd, \
+/* TRISTATE here means output driver is tri-stated */ \
+ .tristate = TEGRA_TRI_##_tri, \
+/* INPUT here means input driver is enabled vs. OUTPUT where it is disabled */ \
+ .io = TEGRA_PIN_##_io, \
+ .lock = TEGRA_PIN_LOCK_DEFAULT, \
+ .od = TEGRA_PIN_OD_DEFAULT, \
+ .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \
+ }
+
+#define I2C_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _od) \
+ { \
+ .pingroup = TEGRA_PINGROUP_##_pingroup, \
+ .func = TEGRA_MUX_##_mux, \
+ .pupd = TEGRA_PUPD_##_pupd, \
+ .tristate = TEGRA_TRI_##_tri, \
+ .io = TEGRA_PIN_##_io, \
+ .lock = TEGRA_PIN_LOCK_##_lock, \
+ .od = TEGRA_PIN_OD_##_od, \
+ .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \
+ }
+
+#define VI_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _ioreset) \
+ { \
+ .pingroup = TEGRA_PINGROUP_##_pingroup, \
+ .func = TEGRA_MUX_##_mux, \
+ .pupd = TEGRA_PUPD_##_pupd, \
+ .tristate = TEGRA_TRI_##_tri, \
+ .io = TEGRA_PIN_##_io, \
+ .lock = TEGRA_PIN_LOCK_##_lock, \
+ .od = TEGRA_PIN_OD_DEFAULT, \
+ .ioreset = TEGRA_PIN_IO_RESET_##_ioreset \
+ }
+
+static __initdata struct tegra_pingroup_config colibri_t30_pinmux[] = {
+//multiplexed KB_ROW_13
+#ifdef COLIBRI_T30_SDMMC4B
+ I2C_PINMUX(CAM_I2C_SCL, POPSDMMC4, PULL_UP, NORMAL, INPUT, DEFAULT, DISABLE),
+#else
+ I2C_PINMUX(CAM_I2C_SCL, I2C3, NORMAL, TRISTATE, OUTPUT, DEFAULT, DISABLE),
+#endif
+//multiplexed KB_ROW_14
+#ifdef COLIBRI_T30_SDMMC4B
+ I2C_PINMUX(CAM_I2C_SDA, POPSDMMC4, PULL_UP, NORMAL, INPUT, DEFAULT, DISABLE),
+#else
+ I2C_PINMUX(CAM_I2C_SDA, I2C3, NORMAL, TRISTATE, OUTPUT, DEFAULT, DISABLE),
+#endif
+//multiplexed KB_ROW_10
+#ifdef COLIBRI_T30_SDMMC4B
+ DEFAULT_PINMUX(CAM_MCLK, POPSDMMC4, NORMAL, NORMAL, INPUT),
+#else
+ DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, NORMAL, TRISTATE, OUTPUT),
+#endif
+
+ DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CLK1_REQ, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(CLK2_OUT, EXTPERIPH2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK2_REQ, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(CLK3_OUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(CLK3_REQ, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+
+ DEFAULT_PINMUX(CLK_32K_OUT, RSVD1, NORMAL, TRISTATE, OUTPUT),
+
+ DEFAULT_PINMUX(CRT_HSYNC, CRT, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CRT_VSYNC, CRT, NORMAL, NORMAL, OUTPUT),
+
+ DEFAULT_PINMUX(DAP1_DIN, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DOUT, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_FS, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_SCLK, GMI, NORMAL, NORMAL, INPUT),
+
+//multiplexed LCD_D23
+ DEFAULT_PINMUX(DAP2_DIN, GMI, NORMAL, TRISTATE, OUTPUT),
+//multiplexed LCD_D22
+ DEFAULT_PINMUX(DAP2_DOUT, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(DAP2_FS, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_SCLK, GMI, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(DAP3_DIN, I2S2, NORMAL, NORMAL, INPUT),
+// DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, OUTPUT),
+// DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(DAP4_DIN, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_DOUT, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_FS, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_SCLK, GMI, NORMAL, NORMAL, INPUT),
+
+ I2C_PINMUX(DDC_SCL, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+ I2C_PINMUX(DDC_SDA, I2C4, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+
+ I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+ I2C_PINMUX(GEN1_I2C_SDA, I2C1, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+
+ I2C_PINMUX(GEN2_I2C_SCL, RSVD3, PULL_UP, NORMAL, INPUT, DEFAULT, DISABLE),
+ I2C_PINMUX(GEN2_I2C_SDA, RSVD3, PULL_UP, NORMAL, INPUT, DEFAULT, DISABLE),
+
+ DEFAULT_PINMUX(GMI_A16, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A17, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A18, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A19, UARTD, NORMAL, NORMAL, INPUT),
+#ifdef COLIBRI_T30_V10
+ DEFAULT_PINMUX(GMI_AD0, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD1, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD2, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD3, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD4, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD5, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD6, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD7, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD8, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD9, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD10, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD11, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD12, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD13, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD14, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD15, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_ADV_N, NAND, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_CLK, NAND, NORMAL, NORMAL, OUTPUT),
+#else /* COLIBRI_T30_V10 */
+ DEFAULT_PINMUX(GMI_AD0, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD1, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD2, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD3, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD4, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD5, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD6, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD7, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD8, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD9, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD10, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD11, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD12, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD13, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD14, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD15, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_ADV_N, GMI, NORMAL, NORMAL, INPUT),
+//multiplexed OWR
+ DEFAULT_PINMUX(GMI_CLK, GMI, NORMAL, TRISTATE, OUTPUT),
+#endif /* COLIBRI_T30_V10 */
+ DEFAULT_PINMUX(GMI_CS0_N, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_CS1_N, RSVD1, NORMAL, NORMAL, INPUT),
+#ifdef COLIBRI_T30_V10
+ DEFAULT_PINMUX(GMI_CS2_N, NAND, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_CS3_N, NAND, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_CS4_N, NAND, NORMAL, NORMAL, OUTPUT),
+#else /* COLIBRI_T30_V10 */
+ DEFAULT_PINMUX(GMI_CS2_N, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_CS3_N, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_CS4_N, GMI, NORMAL, NORMAL, INPUT),
+#endif /* COLIBRI_T30_V10 */
+ DEFAULT_PINMUX(GMI_CS6_N, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_CS7_N, GMI, NORMAL, NORMAL, INPUT),
+#ifdef COLIBRI_T30_V10
+ DEFAULT_PINMUX(GMI_DQS, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_IORDY, NAND, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_OE_N, NAND, NORMAL, NORMAL, OUTPUT),
+#else /* COLIBRI_T30_V10 */
+ DEFAULT_PINMUX(GMI_DQS, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+//multiplexed GMI_WAIT
+ DEFAULT_PINMUX(GMI_IORDY, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_OE_N, GMI, NORMAL, NORMAL, INPUT),
+#endif /* COLIBRI_T30_V10 */
+ DEFAULT_PINMUX(GMI_RST_N, GMI, NORMAL, NORMAL, INPUT),
+#ifdef COLIBRI_T30_V10
+ DEFAULT_PINMUX(GMI_WAIT, NAND, NORMAL, NORMAL, INPUT),
+//GPIO C7: eMMC vs. NAND flash detection
+ DEFAULT_PINMUX(GMI_WP_N, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_WR_N, NAND, NORMAL, NORMAL, OUTPUT),
+#else /* COLIBRI_T30_V10 */
+//multiplexed GMI_IORDY
+ DEFAULT_PINMUX(GMI_WAIT, GMI, NORMAL, TRISTATE, OUTPUT),
+//GPIO PU6: MMC_CD
+ DEFAULT_PINMUX(GMI_WP_N, RSVD1, NORMAL, NORMAL, INPUT),
+//gated, multiplexed LCD_CS1_N or LCD_WR_N
+ DEFAULT_PINMUX(GMI_WR_N, GMI, NORMAL, NORMAL, INPUT),
+#endif /* COLIBRI_T30_V10 */
+
+//multiplexed KB_ROW_12
+#ifdef COLIBRI_T30_SDMMC4B
+ DEFAULT_PINMUX(GPIO_PBB0, POPSDMMC4, PULL_UP, NORMAL, INPUT),
+#else
+ DEFAULT_PINMUX(GPIO_PBB0, RSVD1, NORMAL, TRISTATE, OUTPUT),
+#endif
+//multiplexed KB_ROW_15
+#ifdef COLIBRI_T30_SDMMC4B
+ DEFAULT_PINMUX(GPIO_PBB3, POPSDMMC4, PULL_UP, NORMAL, INPUT),
+#else
+ DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, TRISTATE, OUTPUT),
+#endif
+ DEFAULT_PINMUX(GPIO_PBB4, VGP4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB5, VGP5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB6, VGP6, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB7, RSVD1, NORMAL, NORMAL, INPUT),
+
+//multiplexed KB_ROW_11
+#ifdef COLIBRI_T30_SDMMC4B
+ DEFAULT_PINMUX(GPIO_PCC1, POPSDMMC4, NORMAL, NORMAL, INPUT),
+#else
+ DEFAULT_PINMUX(GPIO_PCC1, RSVD1, NORMAL, TRISTATE, OUTPUT),
+#endif
+#ifdef COLIBRI_T30_SDMMC4B
+//when used for SDMMC4: 10k to VDDIO_CAM
+ DEFAULT_PINMUX(GPIO_PCC2, POPSDMMC4, PULL_UP, NORMAL, INPUT),
+#else /* COLIBRI_T30_SDMMC4B */
+//multiplexed VI_D11
+#ifdef COLIBRI_T30_VI
+ DEFAULT_PINMUX(GPIO_PCC2, RSVD1, NORMAL, TRISTATE, OUTPUT),
+#else
+ DEFAULT_PINMUX(GPIO_PCC2, RSVD1, PULL_UP, NORMAL, INPUT),
+#endif
+#endif /* COLIBRI_T30_SDMMC4B */
+
+ DEFAULT_PINMUX(GPIO_PU0, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU1, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU2, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU3, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU4, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU5, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU6, GMI, NORMAL, NORMAL, INPUT),
+
+//GPIO V0: touch pendown int
+ DEFAULT_PINMUX(GPIO_PV0, RSVD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV1, RSVD, NORMAL, NORMAL, INPUT),
+#ifdef COLIBRI_T30_VI
+//multiplexed VI_D0
+ DEFAULT_PINMUX(GPIO_PV2, RSVD1, NORMAL, TRISTATE, OUTPUT),
+//multiplexed VI_D8
+ DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, TRISTATE, OUTPUT),
+#else
+//GPIO V2: BL_ON
+ DEFAULT_PINMUX(GPIO_PV2, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, NORMAL, INPUT),
+#endif
+
+ DEFAULT_PINMUX(HDMI_CEC, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+//GPIO N7: HOTPLUG_DETECT
+ DEFAULT_PINMUX(HDMI_INT, RSVD0, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(JTAG_RTCK, RTCK, NORMAL, NORMAL, OUTPUT),
+
+//all tristate?
+ DEFAULT_PINMUX(KB_COL0, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL1, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL2, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL3, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL4, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL5, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL6, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL7, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW0, RSVD2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW1, RSVD2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW2, RSVD2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW3, RSVD2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW4, RSVD3, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW5, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW6, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW7, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW8, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW9, KBC, NORMAL, TRISTATE, INPUT),
+
+//multiplexed SDMMC4.B
+#ifdef COLIBRI_T30_SDMMC4B
+ DEFAULT_PINMUX(KB_ROW10, KBC, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW11, KBC, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW13, KBC, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW14, KBC, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW15, KBC, NORMAL, TRISTATE, OUTPUT),
+#else
+ DEFAULT_PINMUX(KB_ROW10, SDMMC2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW11, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW12, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW13, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW14, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW15, SDMMC2, PULL_UP, NORMAL, INPUT),
+#endif
+
+ DEFAULT_PINMUX(LCD_CS0_N, RSVD, NORMAL, NORMAL, INPUT),
+//multiplexed with SDMMC3_DAT5 gated GMI_WR_N
+ DEFAULT_PINMUX(LCD_CS1_N, RSVD2, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D0, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D1, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D2, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D3, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D4, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D5, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D6, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D7, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D9, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D10, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D11, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D12, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D13, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D14, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D15, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D16, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D17, DISPLAYA, NORMAL, NORMAL, INPUT),
+
+//multiplexed
+ DEFAULT_PINMUX(LCD_D18, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D19, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D20, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D21, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D22, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D23, DISPLAYA, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(LCD_DC0, RSVD1, NORMAL, NORMAL, INPUT),
+//GPIO D2: THERMD_ALERT_N
+ DEFAULT_PINMUX(LCD_DC1, RSVD1, NORMAL, NORMAL, INPUT),
+//multiplexed LCD_M1
+ DEFAULT_PINMUX(LCD_DE, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_HSYNC, DISPLAYA, NORMAL, NORMAL, INPUT),
+//multiplexed LCD_DE
+ DEFAULT_PINMUX(LCD_M1, RSVD1, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_PCLK, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_PWR0, DISPLAYA, NORMAL, NORMAL, INPUT),
+//multiplexed VI_VSYNC
+#ifdef COLIBRI_T30_VI
+ DEFAULT_PINMUX(LCD_PWR1, RSVD1, NORMAL, TRISTATE, OUTPUT),
+#else
+ DEFAULT_PINMUX(LCD_PWR1, RSVD1, NORMAL, NORMAL, INPUT),
+#endif
+ DEFAULT_PINMUX(LCD_PWR2, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(LCD_SCK, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_SDIN, RSVD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_SDOUT, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_VSYNC, DISPLAYA, NORMAL, NORMAL, INPUT),
+//multiplexed with SDMMC3_DAT4 gated GMI_WR_N
+#if !defined(CONFIG_CAN_SJA1000) && !defined(CONFIG_CAN_SJA1000_MODULE)
+ DEFAULT_PINMUX(LCD_WR_N, RSVD, NORMAL, NORMAL, INPUT),
+#else /* CONFIG_CAN_SJA1000 & CONFIG_CAN_SJA1000_MODULE */
+ DEFAULT_PINMUX(LCD_WR_N, RSVD, NORMAL, TRISTATE, INPUT),
+#endif /* CONFIG_CAN_SJA1000 & CONFIG_CAN_SJA1000_MODULE */
+//multiplexed GMI_CLK
+ DEFAULT_PINMUX(OWR, OWR, NORMAL, NORMAL, INPUT),
+//GPIO DD2: LAN_VBUS
+ DEFAULT_PINMUX(PEX_L0_CLKREQ_N, RSVD2, NORMAL, NORMAL, OUTPUT),
+//GPIO DD0: LAN_RESET
+ DEFAULT_PINMUX(PEX_L0_PRSNT_N, RSVD2, NORMAL, NORMAL, OUTPUT),
+//GPIO DD1: LAN_EXTWAKEUP
+ DEFAULT_PINMUX(PEX_L0_RST_N, RSVD2, NORMAL, NORMAL, INPUT),
+//multiplexed VI_D9
+#ifdef COLIBRI_T30_VI
+ DEFAULT_PINMUX(PEX_L1_CLKREQ_N, RSVD2, NORMAL, TRISTATE, OUTPUT),
+#else
+ DEFAULT_PINMUX(PEX_L1_CLKREQ_N, RSVD2, NORMAL, NORMAL, INPUT),
+#endif
+ DEFAULT_PINMUX(PEX_L1_PRSNT_N, RSVD2, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+#ifdef COLIBRI_T30_VI
+//multiplexed VI_D10
+ DEFAULT_PINMUX(PEX_L1_RST_N, RSVD2, NORMAL, TRISTATE, OUTPUT),
+//multiplexed VI_HSYNC
+ DEFAULT_PINMUX(PEX_L2_CLKREQ_N, RSVD2, NORMAL, TRISTATE, OUTPUT),
+#else
+ DEFAULT_PINMUX(PEX_L1_RST_N, RSVD2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L2_CLKREQ_N, RSVD2, NORMAL, NORMAL, INPUT),
+#endif
+ DEFAULT_PINMUX(PEX_L2_PRSNT_N, RSVD2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L2_RST_N, RSVD2, PULL_UP, NORMAL, INPUT),
+//GPIO DD3: LAN_PME
+ DEFAULT_PINMUX(PEX_WAKE_N, RSVD2, NORMAL, NORMAL, INPUT),
+
+/* Power I2C pinmux */
+ I2C_PINMUX(PWR_I2C_SCL, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+ I2C_PINMUX(PWR_I2C_SDA, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
+
+#ifdef COLIBRI_T30_VI
+//multiplexed VI_PCLK
+ DEFAULT_PINMUX(SDMMC1_CLK, RSVD1, NORMAL, TRISTATE, OUTPUT),
+//multiplexed VI_D1
+ DEFAULT_PINMUX(SDMMC1_CMD, RSVD1, NORMAL, TRISTATE, OUTPUT),
+//multiplexed VI_D2
+ DEFAULT_PINMUX(SDMMC1_DAT0, RSVD1, NORMAL, TRISTATE, OUTPUT),
+//multiplexed VI_D3
+ DEFAULT_PINMUX(SDMMC1_DAT1, RSVD1, NORMAL, TRISTATE, OUTPUT),
+//multiplexed VI_D4
+ DEFAULT_PINMUX(SDMMC1_DAT2, RSVD1, NORMAL, TRISTATE, OUTPUT),
+//multiplexed VI_D5
+ DEFAULT_PINMUX(SDMMC1_DAT3, RSVD1, NORMAL, TRISTATE, OUTPUT),
+#else
+ DEFAULT_PINMUX(SDMMC1_CLK, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_CMD, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT0, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT1, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT2, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT3, RSVD1, NORMAL, NORMAL, INPUT),
+#endif
+
+ DEFAULT_PINMUX(SDMMC3_CLK, PWM2, NORMAL, NORMAL, INPUT),
+//multiplexed VI_D6
+#ifdef COLIBRI_T30_VI
+ DEFAULT_PINMUX(SDMMC3_CMD, SDMMC3, NORMAL, TRISTATE, OUTPUT),
+#else
+ DEFAULT_PINMUX(SDMMC3_CMD, PWM3, NORMAL, NORMAL, INPUT),
+#endif
+ DEFAULT_PINMUX(SDMMC3_DAT0, RSVD0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT1, RSVD0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT2, PWM1, NORMAL, NORMAL, INPUT),
+//multiplexed VI_D7
+#ifdef COLIBRI_T30_VI
+ DEFAULT_PINMUX(SDMMC3_DAT3, RSVD0, NORMAL, TRISTATE, OUTPUT),
+#else
+ DEFAULT_PINMUX(SDMMC3_DAT3, PWM0, NORMAL, NORMAL, INPUT),
+#endif
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+//not tri-stating GMI_WR_N on nPWE SODIMM pin 99
+ DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT),
+#else /* CONFIG_CAN_SJA1000) | CONFIG_CAN_SJA1000_MODULE */
+//tri-stating GMI_WR_N on nPWE SODIMM pin 99
+ DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, PULL_UP, TRISTATE, OUTPUT),
+#endif /* CONFIG_CAN_SJA1000) | CONFIG_CAN_SJA1000_MODULE */
+//not tri-stating GMI_WR_N on RDnWR SODIMM pin 93
+ DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT),
+//multiplexed ULPI_STP used as SSPFRM
+ DEFAULT_PINMUX(SDMMC3_DAT6, SPDIF, NORMAL, TRISTATE, OUTPUT),
+//multiplexed ULPI_CLK used as SSPTXD
+ DEFAULT_PINMUX(SDMMC3_DAT7, SPDIF, NORMAL, TRISTATE, OUTPUT),
+
+//eMMC
+#ifdef COLIBRI_T30_SDMMC4B
+ DEFAULT_PINMUX(SDMMC4_CLK, NAND, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_CMD, NAND, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT0, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT1, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT2, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT3, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT4, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT5, VGP3, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT6, VGP4, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT7, VGP5, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_RST_N, RSVD1, NORMAL, TRISTATE, OUTPUT),
+#else /* COLIBRI_T30_SDMMC4B */
+ DEFAULT_PINMUX(SDMMC4_CLK, SDMMC4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_CMD, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT0, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT1, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT2, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT3, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT4, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT5, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT6, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT7, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_RST_N, RSVD1, PULL_DOWN, NORMAL, INPUT),
+#endif /* COLIBRI_T30_SDMMC4B */
+
+//GPIO K6: USB_ID, multiplexed ACC1_DETECT
+ DEFAULT_PINMUX(SPDIF_IN, HDA, PULL_UP, NORMAL, INPUT),
+//GPIO K5: USBC_DET(VBUS), multiplexed USB1_VBUS
+ DEFAULT_PINMUX(SPDIF_OUT, RSVD1, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(SPI1_CS0_N, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_MISO, RSVD3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_MOSI, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_SCK, GMI, NORMAL, NORMAL, INPUT),
+//multiplexed LCD_D18
+ DEFAULT_PINMUX(SPI2_CS0_N, GMI, NORMAL, TRISTATE, OUTPUT),
+//GPIO W2: USBH_PEN
+ DEFAULT_PINMUX(SPI2_CS1_N, SPI2, PULL_UP, NORMAL, INPUT),
+//GPIO W3: USBH_OC
+ DEFAULT_PINMUX(SPI2_CS2_N, SPI2, NORMAL, NORMAL, INPUT),
+//multiplexed LCD_D20
+ DEFAULT_PINMUX(SPI2_MISO, GMI, NORMAL, TRISTATE, OUTPUT),
+//multiplexed LCD_D21
+ DEFAULT_PINMUX(SPI2_MOSI, GMI, NORMAL, TRISTATE, OUTPUT),
+//multiplexed LCD_D19
+ DEFAULT_PINMUX(SPI2_SCK, GMI, NORMAL, TRISTATE, OUTPUT),
+
+ DEFAULT_PINMUX(SYS_CLK_REQ, SYSCLK, NORMAL, TRISTATE, OUTPUT),
+
+ DEFAULT_PINMUX(UART2_CTS_N, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART2_RTS_N, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART2_TXD, IRDA, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(UART3_CTS_N, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_RTS_N, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_RXD, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_TXD, GMI, NORMAL, NORMAL, INPUT),
+
+//multiplexed SDMMC3_DAT7
+ DEFAULT_PINMUX(ULPI_CLK, SPI1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA0, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA1, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA2, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA3, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA4, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA5, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA6, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA7, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DIR, SPI1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_NXT, SPI1, NORMAL, NORMAL, INPUT),
+//multiplexed SDMMC3_DAT6
+ DEFAULT_PINMUX(ULPI_STP, SPI1, NORMAL, NORMAL, INPUT),
+
+//VI pins are all input level-shifted and multiplexed
+//unused VI pins could disable input drivers
+ VI_PINMUX(VI_D0, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D1, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D2, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D3, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D4, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D5, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D6, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D7, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D8, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D9, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D10, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D11, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_HSYNC, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+//GPIO T1: EN_MIC_GND
+ DEFAULT_PINMUX(VI_MCLK, VI, NORMAL, NORMAL, OUTPUT),
+ VI_PINMUX(VI_PCLK, VI, PULL_UP, TRISTATE, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_VSYNC, VI, NORMAL, TRISTATE, INPUT, DISABLE, DISABLE),
+};
+
+#define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \
+ { \
+ .gpio_nr = _gpio, \
+ .is_input = _is_input, \
+ .value = _value, \
+ }
+
+static struct gpio_init_pin_info colibri_t30_init_gpio_mode[] = {
+};
+
+static void __init colibri_t30_gpio_init_configure(void)
+{
+ int len;
+ int i;
+ struct gpio_init_pin_info *pins_info;
+
+ len = ARRAY_SIZE(colibri_t30_init_gpio_mode);
+ pins_info = colibri_t30_init_gpio_mode;
+
+ for (i = 0; i < len; ++i) {
+ tegra_gpio_init_configure(pins_info->gpio_nr,
+ pins_info->is_input,
+ pins_info->value);
+ pins_info++;
+ }
+}
+
+int __init colibri_t30_pinmux_init(void)
+{
+ colibri_t30_gpio_init_configure();
+
+ tegra_pinmux_config_table(colibri_t30_pinmux,
+ ARRAY_SIZE(colibri_t30_pinmux));
+ tegra_drive_pinmux_config_table(colibri_t30_drive_pinmux,
+ ARRAY_SIZE(colibri_t30_drive_pinmux));
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/board-colibri_t30-power.c b/arch/arm/mach-tegra/board-colibri_t30-power.c
new file mode 100644
index 000000000000..9a76b110cbf6
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t30-power.c
@@ -0,0 +1,503 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t30-power.c
+ *
+ * Copyright (C) 2012 Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <asm/mach-types.h>
+
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/mfd/max77663-core.h>
+#include <linux/mfd/tps6591x.h>
+#include <linux/pda_power.h>
+#include <linux/platform_device.h>
+//#include <linux/power/gpio-charger.h>
+#include <linux/regulator/fixed.h>
+//#include <linux/regulator/gpio-switch-regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/tps62360.h>
+#include <linux/regulator/tps6591x-regulator.h>
+#include <linux/resource.h>
+
+#include <mach/edp.h>
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+#include <mach/pinmux.h>
+
+#include "board-colibri_t30.h"
+#include "board.h"
+#include "gpio-names.h"
+#include "tegra3_tsensor.h"
+#include "pm.h"
+#include "wakeups.h"
+#include "wakeups-t3.h"
+
+#define PMC_CTRL 0x0
+#define PMC_CTRL_INTR_LOW (1 << 17)
+
+/* SW1: +V1.35_VDDIO_DDR */
+static struct regulator_consumer_supply tps6591x_vdd1_supply_0[] = {
+ REGULATOR_SUPPLY("mem_vddio_ddr", NULL),
+ REGULATOR_SUPPLY("t30_vddio_ddr", NULL),
+};
+
+/* SW2: unused */
+static struct regulator_consumer_supply tps6591x_vdd2_supply_0[] = {
+ REGULATOR_SUPPLY("unused_rail_vdd2", NULL),
+};
+
+/* SW CTRL: +V1.0_VDD_CPU */
+static struct regulator_consumer_supply tps6591x_vddctrl_supply_0[] = {
+ REGULATOR_SUPPLY("vdd_cpu_pmu", NULL),
+ REGULATOR_SUPPLY("vdd_cpu", NULL),
+//!=vddio_sys!
+ REGULATOR_SUPPLY("vdd_sys", NULL),
+};
+
+/* SWIO: +V1.8 */
+static struct regulator_consumer_supply tps6591x_vio_supply_0[] = {
+ REGULATOR_SUPPLY("vdd_gen1v8", NULL),
+ REGULATOR_SUPPLY("avdd_usb_pll", NULL),
+ REGULATOR_SUPPLY("avdd_osc", NULL),
+ REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.3"),
+ REGULATOR_SUPPLY("pwrdet_sdmmc4", NULL),
+ REGULATOR_SUPPLY("vdd1v8_satelite", NULL),
+ REGULATOR_SUPPLY("vddio_vi", NULL),
+ REGULATOR_SUPPLY("pwrdet_vi", NULL),
+ REGULATOR_SUPPLY("ldo1", NULL),
+ REGULATOR_SUPPLY("ldo2", NULL),
+ REGULATOR_SUPPLY("ldo6", NULL),
+ REGULATOR_SUPPLY("ldo7", NULL),
+ REGULATOR_SUPPLY("ldo8", NULL),
+ REGULATOR_SUPPLY("vcore_audio", NULL),
+ REGULATOR_SUPPLY("avcore_audio", NULL),
+ REGULATOR_SUPPLY("vcore1_lpddr2", NULL),
+ REGULATOR_SUPPLY("vcom_1v8", NULL),
+ REGULATOR_SUPPLY("pmuio_1v8", NULL),
+ REGULATOR_SUPPLY("avdd_ic_usb", NULL),
+};
+
+/* unused */
+static struct regulator_consumer_supply tps6591x_ldo1_supply_0[] = {
+ REGULATOR_SUPPLY("unused_rail_ldo1", NULL),
+};
+
+/* EN_+V3.3 switching via FET: +V3.3_AUDIO_AVDD_S, +V3.3 and +V1.8_VDD_LAN
+ see also v3_3 fixed supply */
+static struct regulator_consumer_supply tps6591x_ldo2_supply_0[] = {
+ REGULATOR_SUPPLY("en_V3_3", NULL),
+};
+
+/* unused in Colibri T30, used in Apalis T30 */
+static struct regulator_consumer_supply tps6591x_ldo3_supply_0[] = {
+ REGULATOR_SUPPLY("avdd_dsi_csi", NULL),
+ REGULATOR_SUPPLY("pwrdet_mipi", NULL),
+};
+
+/* +V1.2_VDD_RTC */
+static struct regulator_consumer_supply tps6591x_ldo4_supply_0[] = {
+ REGULATOR_SUPPLY("vdd_rtc", NULL),
+};
+
+/* +V2.8_AVDD_VDAC */
+//only required for analog RGB
+static struct regulator_consumer_supply tps6591x_ldo5_supply_0[] = {
+ REGULATOR_SUPPLY("avdd_vdac", NULL),
+};
+
+/* +V1.05_AVDD_PLLE */
+static struct regulator_consumer_supply tps6591x_ldo6_supply_0[] = {
+ REGULATOR_SUPPLY("avdd_plle", NULL),
+};
+
+/* +V1.2_AVDD_PLL */
+static struct regulator_consumer_supply tps6591x_ldo7_supply_0[] = {
+ REGULATOR_SUPPLY("avdd_plla_p_c_s", NULL),
+ REGULATOR_SUPPLY("avdd_pllm", NULL),
+ REGULATOR_SUPPLY("avdd_pllu_d", NULL),
+ REGULATOR_SUPPLY("avdd_pllu_d2", NULL),
+ REGULATOR_SUPPLY("avdd_pllx", NULL),
+};
+
+/* +V1.0_VDD_DDR_HS */
+static struct regulator_consumer_supply tps6591x_ldo8_supply_0[] = {
+ REGULATOR_SUPPLY("vdd_ddr_hs", NULL),
+};
+
+#define TPS_PDATA_INIT(_name, _sname, _minmv, _maxmv, _supply_reg, _always_on, \
+ _boot_on, _apply_uv, _init_uV, _init_enable, _init_apply, _ectrl, _flags) \
+ static struct tps6591x_regulator_platform_data pdata_##_name##_##_sname = \
+ { \
+ .regulator = { \
+ .constraints = { \
+ .min_uV = (_minmv)*1000, \
+ .max_uV = (_maxmv)*1000, \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL | \
+ REGULATOR_MODE_STANDBY), \
+ .valid_ops_mask = (REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_STATUS | \
+ REGULATOR_CHANGE_VOLTAGE), \
+ .always_on = _always_on, \
+ .boot_on = _boot_on, \
+ .apply_uV = _apply_uv, \
+ }, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(tps6591x_##_name##_supply_##_sname), \
+ .consumer_supplies = tps6591x_##_name##_supply_##_sname, \
+ .supply_regulator = _supply_reg, \
+ }, \
+ .init_uV = _init_uV * 1000, \
+ .init_enable = _init_enable, \
+ .init_apply = _init_apply, \
+ .ectrl = _ectrl, \
+ .flags = _flags, \
+ }
+
+TPS_PDATA_INIT(vdd1, 0, 1350, 1350, 0, 1, 1, 0, -1, 0, 0, 0, 0);
+TPS_PDATA_INIT(vdd2, 0, 1050, 1050, 0, 0, 1, 0, -1, 0, 0, EXT_CTRL_SLEEP_OFF, 0);
+TPS_PDATA_INIT(vddctrl, 0, 800, 1300, 0, 1, 1, 0, -1, 0, 0, EXT_CTRL_EN1, 0);
+TPS_PDATA_INIT(vio, 0, 1800, 1800, 0, 1, 1, 0, -1, 0, 0, 0, 0);
+
+TPS_PDATA_INIT(ldo1, 0, 1000, 3300, tps6591x_rails(VIO), 0, 0, 0, -1, 0, 1, 0, 0);
+/* Make sure EN_+V3.3 is always on! */
+TPS_PDATA_INIT(ldo2, 0, 1200, 1200, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 1, 0, 0);
+
+TPS_PDATA_INIT(ldo3, 0, 1200, 1200, 0, 0, 0, 0, -1, 0, 0, 0, 0);
+TPS_PDATA_INIT(ldo4, 0, 900, 1400, 0, 1, 0, 0, -1, 0, 0, 0, LDO_LOW_POWER_ON_SUSPEND);
+TPS_PDATA_INIT(ldo5, 0, 2800, 2800, 0, 0, 0, 0, -1, 0, 0, 0, 0);
+/* AVDD_PLLE should be 1.05V, but ldo_6 can not be adjusted in a 50mV granularity */
+TPS_PDATA_INIT(ldo6, 0, 1000, 1100, tps6591x_rails(VIO), 0, 0, 1, -1, 0, 0, 0, 0);
+
+TPS_PDATA_INIT(ldo7, 0, 1200, 1200, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 0, EXT_CTRL_SLEEP_OFF, LDO_LOW_POWER_ON_SUSPEND);
+TPS_PDATA_INIT(ldo8, 0, 1000, 1000, tps6591x_rails(VIO), 1, 0, 0, -1, 0, 0, EXT_CTRL_SLEEP_OFF, LDO_LOW_POWER_ON_SUSPEND);
+
+#if defined(CONFIG_RTC_DRV_TPS6591x)
+static struct tps6591x_rtc_platform_data rtc_data = {
+ .irq = TPS6591X_IRQ_BASE + TPS6591X_INT_RTC_ALARM,
+ .time = {
+ .tm_year = 2000,
+ .tm_mon = 0,
+ .tm_mday = 1,
+ .tm_hour = 0,
+ .tm_min = 0,
+ .tm_sec = 0,
+ },
+};
+
+#define TPS_RTC_REG() \
+ { \
+ .id = 0, \
+ .name = "rtc_tps6591x", \
+ .platform_data = &rtc_data, \
+ }
+#endif
+
+#define TPS_REG(_id, _name, _sname) \
+ { \
+ .id = TPS6591X_ID_##_id, \
+ .name = "tps6591x-regulator", \
+ .platform_data = &pdata_##_name##_##_sname, \
+ }
+
+static struct tps6591x_subdev_info colibri_t30_tps_devs[] = {
+ TPS_REG(VDD_1, vdd1, 0),
+ TPS_REG(VDD_2, vdd2, 0),
+ TPS_REG(VDDCTRL, vddctrl, 0),
+ TPS_REG(VIO, vio, 0),
+ TPS_REG(LDO_1, ldo1, 0),
+ TPS_REG(LDO_2, ldo2, 0),
+ TPS_REG(LDO_3, ldo3, 0),
+ TPS_REG(LDO_4, ldo4, 0),
+ TPS_REG(LDO_5, ldo5, 0),
+ TPS_REG(LDO_6, ldo6, 0),
+ TPS_REG(LDO_7, ldo7, 0),
+ TPS_REG(LDO_8, ldo8, 0),
+#if defined(CONFIG_RTC_DRV_TPS6591x)
+ TPS_RTC_REG(),
+#endif
+};
+
+static struct tps6591x_sleep_keepon_data tps_slp_keepon = {
+ .clkout32k_keepon = 1,
+};
+
+static struct tps6591x_platform_data tps_platform = {
+ .irq_base = TPS6591X_IRQ_BASE,
+ .gpio_base = TPS6591X_GPIO_BASE,
+ .dev_slp_en = true,
+ .slp_keepon = &tps_slp_keepon,
+ .use_power_off = true,
+};
+
+static struct i2c_board_info __initdata colibri_t30_regulators[] = {
+ {
+ I2C_BOARD_INFO("tps6591x", 0x2D),
+//PWR_INT_IN wake18
+ .irq = INT_EXTERNAL_PMU,
+ .platform_data = &tps_platform,
+ },
+};
+
+/* TPS62362 DC-DC converter
+ SW: +V1.2_VDD_CORE
+ Note: Colibri T30 V1.0 have TPS62360 with different voltage levels at startup */
+static struct regulator_consumer_supply tps6236x_dcdc_supply[] = {
+ REGULATOR_SUPPLY("vdd_core", NULL),
+};
+
+static struct tps62360_regulator_platform_data tps6236x_pdata = {
+ .reg_init_data = { \
+ .constraints = { \
+ .min_uV = 900000, \
+ .max_uV = 1400000, \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL | \
+ REGULATOR_MODE_STANDBY), \
+ .valid_ops_mask = (REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_STATUS | \
+ REGULATOR_CHANGE_VOLTAGE), \
+ .always_on = 1, \
+ .boot_on = 1, \
+ .apply_uV = 0, \
+ }, \
+ .num_consumer_supplies = ARRAY_SIZE(tps6236x_dcdc_supply), \
+ .consumer_supplies = tps6236x_dcdc_supply, \
+ }, \
+ .en_discharge = true, \
+ .vsel0_gpio = -1, \
+ .vsel1_gpio = -1, \
+ .vsel0_def_state = 1, \
+ .vsel1_def_state = 1, \
+};
+
+static struct i2c_board_info __initdata tps6236x_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("tps62360", 0x60),
+ .platform_data = &tps6236x_pdata,
+ },
+};
+
+/* Macro for defining fixed regulator sub device data */
+#define FIXED_SUPPLY(_name) "fixed_reg_"#_name
+#define FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, \
+ _boot_on, _gpio_nr, _active_high, _boot_state, \
+ _millivolts, _od_state) \
+ static struct regulator_init_data ri_data_##_var = \
+ { \
+ .supply_regulator = _in_supply, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(fixed_reg_##_name##_supply), \
+ .consumer_supplies = fixed_reg_##_name##_supply, \
+ .constraints = { \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL), \
+ .valid_ops_mask = (REGULATOR_CHANGE_STATUS), \
+ .always_on = _always_on, \
+ .boot_on = _boot_on, \
+ }, \
+ }; \
+ static struct fixed_voltage_config fixed_reg_##_var##_pdata = \
+ { \
+ .supply_name = FIXED_SUPPLY(_name), \
+ .microvolts = _millivolts * 1000, \
+ .gpio = _gpio_nr, \
+ .enable_high = _active_high, \
+ .enabled_at_boot = _boot_state, \
+ .init_data = &ri_data_##_var, \
+ .gpio_is_open_drain = _od_state, \
+ }; \
+ static struct platform_device fixed_reg_##_var##_dev = { \
+ .name = "reg-fixed-voltage", \
+ .id = _id, \
+ .dev = { \
+ .platform_data = &fixed_reg_##_var##_pdata, \
+ }, \
+ }
+
+#define FIXED_REG(_id, _var, _name, _in_supply, _always_on, _boot_on, \
+ _gpio_nr, _active_high, _boot_state, _millivolts) \
+ FIXED_REG_OD(_id, _var, _name, _in_supply, _always_on, _boot_on, \
+ _gpio_nr, _active_high, _boot_state, _millivolts, false)
+
+#define ADD_FIXED_REG(_name) (&fixed_reg_##_name##_dev)
+
+/* PMU GP6: EN_VDD_HDMI switching via FET: +V1.8_AVDD_HDMI_PLL and +V3.3_AVDD_HDMI */
+static struct regulator_consumer_supply fixed_reg_en_hdmi_supply[] = {
+ REGULATOR_SUPPLY("avdd_hdmi", NULL),
+ REGULATOR_SUPPLY("avdd_hdmi_pll", NULL),
+// REGULATOR_SUPPLY("vdd_3v3_hdmi_cec", NULL),
+};
+
+//EN_VDD_CORE PMIC GPIO2
+//EN_VDD_FUSE PMIC GPIO4
+//EN_VDD_HDMI PMIC GPIO6
+
+FIXED_REG(2, en_hdmi, en_hdmi, NULL, 0, 0, TPS6591X_GPIO_6, true, 1, 1800);
+
+/* +V3.3 is switched on by LDO2, As this can not be modeled we use a fixed
+ regulator without enable, 3.3V must not be switched off anyway.
++V3.3:
+VDD_DDR_RX
+VDDIO_LCD_1
+VDDIO_LCD_2
+VDDIO_CAM
+LM95245
+VDDIO_SYS_01
+VDDIO_SYS_02
+VDDIO_BB
+VDDIO_AUDIO
+VDDIO_GMI_1
+VDDIO_GMI_2
+VDDIO_GMI_3
+VDDIO_UART
+VDDIO_SDMMC1
+AVDD_USB
+VDDIO_SDMMC3
+74AVCAH164245
+VDDIO_PEX_CTL
+TPS65911 VDDIO
+MT29F16G08
+SGTL5000 VDDIO
+STMPE811
+AX88772B VCC3x
+SDIN5D2-2G VCCx */
+static struct regulator_consumer_supply fixed_reg_v3_3_supply[] = {
+ REGULATOR_SUPPLY("avdd_audio", NULL),
+ REGULATOR_SUPPLY("avdd_usb", NULL),
+ REGULATOR_SUPPLY("vddio_sd_slot", "sdhci-tegra.1"),
+ REGULATOR_SUPPLY("vddio_sys", NULL),
+ REGULATOR_SUPPLY("vddio_uart", NULL),
+ REGULATOR_SUPPLY("pwrdet_uart", NULL),
+ REGULATOR_SUPPLY("vddio_audio", NULL),
+ REGULATOR_SUPPLY("pwrdet_audio", NULL),
+ REGULATOR_SUPPLY("vddio_bb", NULL),
+ REGULATOR_SUPPLY("pwrdet_bb", NULL),
+ REGULATOR_SUPPLY("vddio_lcd_pmu", NULL),
+ REGULATOR_SUPPLY("pwrdet_lcd", NULL),
+ REGULATOR_SUPPLY("vddio_cam", NULL),
+ REGULATOR_SUPPLY("pwrdet_cam", NULL),
+ /* if this supply is defined, the sdhci driver tries
+ * to set it to 1.8V */
+// REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.1"),
+ REGULATOR_SUPPLY("pwrdet_sdmmc2", NULL),
+ REGULATOR_SUPPLY("pwrdet_sdmmc1", NULL),
+ REGULATOR_SUPPLY("pwrdet_sdmmc3", NULL),
+ REGULATOR_SUPPLY("pwrdet_pex_ctl", NULL),
+ REGULATOR_SUPPLY("pwrdet_nand", NULL),
+
+ /* SGTL5000 */
+ REGULATOR_SUPPLY("VDDA", "4-000a"),
+ REGULATOR_SUPPLY("VDDIO", "4-000a"),
+};
+
+FIXED_REG(3, v3_3, v3_3, NULL, 1, 1, -1, true, 1, 3300);
+
+/* Gpio switch regulator platform data */
+static struct platform_device *fixed_reg_devs_colibri_t30[] = {
+ ADD_FIXED_REG(en_hdmi),
+ ADD_FIXED_REG(v3_3),
+};
+
+int __init colibri_t30_regulator_init(void)
+{
+ void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+ u32 pmc_ctrl;
+
+ /* configure the power management controller to trigger PMU
+ * interrupts when low */
+
+ pmc_ctrl = readl(pmc + PMC_CTRL);
+ writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);
+
+ /* The regulator details have complete constraints */
+ regulator_has_full_constraints();
+
+ tps_platform.num_subdevs =
+ ARRAY_SIZE(colibri_t30_tps_devs);
+ tps_platform.subdevs = colibri_t30_tps_devs;
+
+ i2c_register_board_info(4, colibri_t30_regulators, 1);
+
+ /* Register the TPS6236x. */
+ pr_info("Registering the device TPS62360\n");
+ i2c_register_board_info(4, tps6236x_boardinfo, 1);
+
+ return 0;
+}
+
+int __init colibri_t20_fixed_regulator_init(void)
+{
+ return platform_add_devices(fixed_reg_devs_colibri_t30, ARRAY_SIZE(fixed_reg_devs_colibri_t30));
+}
+subsys_initcall_sync(colibri_t20_fixed_regulator_init);
+
+static void colibri_t30_board_suspend(int lp_state, enum suspend_stage stg)
+{
+ if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_SUSPEND_BEFORE_CPU))
+ tegra_console_uart_suspend();
+}
+
+static void colibri_t30_board_resume(int lp_state, enum resume_stage stg)
+{
+ if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_RESUME_AFTER_CPU))
+ tegra_console_uart_resume();
+}
+
+static struct tegra_suspend_platform_data colibri_t30_suspend_data = {
+ .cpu_timer = 2000,
+ .cpu_off_timer = 200,
+ .suspend_mode = TEGRA_SUSPEND_LP1,
+ .core_timer = 0x7e7e,
+ .core_off_timer = 0,
+ .corereq_high = true,
+ .sysclkreq_high = true,
+ .cpu_lp2_min_residency = 2000,
+ .board_suspend = colibri_t30_board_suspend,
+ .board_resume = colibri_t30_board_resume,
+};
+
+int __init colibri_t30_suspend_init(void)
+{
+ /* Make core_pwr_req to high */
+ colibri_t30_suspend_data.corereq_high = true;
+
+ /* CORE_PWR_REQ to be high required to enable the dc-dc converter tps62361x */
+ colibri_t30_suspend_data.corereq_high = true;
+
+//required?
+ colibri_t30_suspend_data.cpu_timer = 5000;
+ colibri_t30_suspend_data.cpu_off_timer = 5000;
+
+ tegra_init_suspend(&colibri_t30_suspend_data);
+ return 0;
+}
+
+#ifdef CONFIG_TEGRA_EDP_LIMITS
+int __init colibri_t30_edp_init(void)
+{
+ unsigned int regulator_mA;
+
+ regulator_mA = get_maximum_cpu_current_supported();
+ if (!regulator_mA) {
+ regulator_mA = 6000; /* regular T30/s */
+ }
+ pr_info("%s: CPU regulator %d mA\n", __func__, regulator_mA);
+
+ tegra_init_cpu_edp_limits(regulator_mA);
+ return 0;
+}
+#endif
diff --git a/arch/arm/mach-tegra/board-colibri_t30.c b/arch/arm/mach-tegra/board-colibri_t30.c
new file mode 100644
index 000000000000..db3ab08cbc3d
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t30.c
@@ -0,0 +1,1556 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t30.c
+ *
+ * Copyright (c) 2012-2013 Toradex, Inc.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <linux/can/platform/mcp251x.h>
+#include <linux/can/platform/sja1000.h>
+#include <linux/clk.h>
+#include <linux/colibri_usb.h>
+#include <linux/types.h> /* required by linux/gpio_keys.h */
+#include <linux/gpio_keys.h>
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/leds_pwm.h>
+#include <linux/lm95245.h>
+#include <linux/mfd/stmpe.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/spi/spi.h>
+#include <linux/spi-tegra.h>
+#include <linux/tegra_uart.h>
+
+#include <mach/io_dpd.h>
+#include <mach/sdhci.h>
+#include <mach/tegra_asoc_pdata.h>
+#include <mach/tegra_fiq_debugger.h>
+#include <mach/thermal.h>
+#include <mach/usb_phy.h>
+#include <mach/w1.h>
+
+#include <media/soc_camera.h>
+#include <media/tegra_v4l2_camera.h>
+#include <linux/input/fusion_F0710A.h>
+
+#include "board-colibri_t30.h"
+#include "board.h"
+#include "clock.h"
+#include "devices.h"
+#include "gpio-names.h"
+#include "pm.h"
+
+//from former drivers/mtd/maps/tegra_nor.h
+#define TEGRA_GMI_PHYS 0x70009000
+#define TEGRA_GMI_BASE IO_TO_VIRT(TEGRA_GMI_PHYS)
+#define TEGRA_SNOR_CONFIG_REG (TEGRA_GMI_BASE + 0x00)
+
+//from drivers/mtd/maps/tegra_nor.c
+#define __BITMASK0(len) (BIT(len) - 1)
+#define REG_FIELD(val, start, len) (((val) & __BITMASK0(len)) << (start))
+
+#define TEGRA_SNOR_CONFIG_GO BIT(31)
+#define TEGRA_SNOR_CONFIG_SNOR_CS(val) REG_FIELD((val), 4, 3)
+
+/* Audio */
+
+static struct tegra_asoc_platform_data colibri_t30_audio_sgtl5000_pdata = {
+ .gpio_spkr_en = -1,
+ .gpio_hp_det = -1,
+ .gpio_hp_mute = -1,
+ .gpio_int_mic_en = -1,
+ .gpio_ext_mic_en = -1,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0, /* index of below registered
+ tegra_i2s_device */
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ .is_i2s_master = 1,
+ .sample_size = 16,
+ },
+ .i2s_param[BASEBAND] = {
+ .audio_port_id = -1,
+ },
+ .i2s_param[BT_SCO] = {
+ .audio_port_id = -1,
+ },
+};
+
+static struct platform_device colibri_t30_audio_sgtl5000_device = {
+ .name = "tegra-snd-colibri_t30-sgtl5000",
+ .id = 0,
+ .dev = {
+ .platform_data = &colibri_t30_audio_sgtl5000_pdata,
+ },
+};
+
+/* Camera */
+
+#ifdef CONFIG_TEGRA_CAMERA
+static struct platform_device tegra_camera = {
+ .name = "tegra_camera",
+ .id = -1,
+};
+#endif /* CONFIG_TEGRA_CAMERA */
+
+#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE)
+static void tegra_camera_disable(struct nvhost_device *ndev)
+{
+}
+
+static int tegra_camera_enable(struct nvhost_device *ndev)
+{
+ return 0;
+}
+
+static struct tegra_camera_platform_data tegra_camera_platform_data = {
+ .disable_camera = tegra_camera_disable,
+ .enable_camera = tegra_camera_enable,
+ .flip_h = 0,
+ .flip_v = 0,
+ .port = TEGRA_CAMERA_PORT_VIP,
+};
+
+#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE)
+static struct i2c_board_info camera_i2c_max9526 = {
+ I2C_BOARD_INFO("max9526", 0x21),
+};
+
+static struct soc_camera_link iclink_max9526 = {
+ .board_info = &camera_i2c_max9526,
+ .bus_id = -1, /* This must match the .id of tegra_vi01_device */
+ .i2c_adapter_id = 0,
+};
+
+static struct platform_device soc_camera_max9526 = {
+ .name = "soc-camera-pdrv",
+ .id = 0,
+ .dev = {
+ .platform_data = &iclink_max9526,
+ },
+};
+#endif /* CONFIG_SOC_CAMERA_MAX9526 | CONFIG_SOC_CAMERA_MAX9526_MODULE */
+
+#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE)
+static struct i2c_board_info camera_i2c_adv7180 = {
+ I2C_BOARD_INFO("adv7180", 0x21),
+};
+
+static struct soc_camera_link iclink_adv7180 = {
+ .board_info = &camera_i2c_adv7180,
+ .bus_id = -1, /* This must match the .id of tegra_vi01_device */
+ .i2c_adapter_id = 0,
+};
+
+static struct platform_device soc_camera_adv7180 = {
+ .name = "soc-camera-pdrv",
+ .id = 1,
+ .dev = {
+ .platform_data = &iclink_adv7180,
+ },
+};
+#endif /* CONFIG_VIDEO_ADV7180 | CONFIG_VIDEO_ADV7180_MODULE */
+#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */
+
+/* CAN */
+#if ((defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)) && \
+ (defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)))
+ #error either enable MCP251X or SJA1000 but not both
+#endif
+
+#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)
+/* Colibri EvalBoard V3.1a */
+
+#define CAN_INTERRUPT_GPIO TEGRA_GPIO_PS0 /* active low interrupt (MCP2515 nINT) */
+#define CAN_RESET_GPIO TEGRA_GPIO_PK4 /* active high reset (not MCP2515 nRESET) */
+
+static int __init colibri_t20_mcp2515_setup(struct spi_device *spi)
+{
+ int gpio_status;
+
+ printk("Colibri EvalBoard V3.1a CAN Initialisation\n");
+
+ /* configure MCP2515 reset line as output and pull high into reset */
+ gpio_status = gpio_request(CAN_RESET_GPIO, "CAN_RESET_GPIO");
+ if (gpio_status < 0)
+ pr_warning("CAN_RESET_GPIO request GPIO FAILED\n");
+ gpio_status = gpio_direction_output(CAN_RESET_GPIO, 1);
+ if (gpio_status < 0)
+ pr_warning("CAN_RESET_GPIO request GPIO DIRECTION FAILED\n");
+
+ udelay(2);
+
+ /* pull out of reset */
+ gpio_set_value(CAN_RESET_GPIO, 0);
+
+ return 0;
+}
+
+static struct mcp251x_platform_data mcp251x_pdata = {
+ .board_specific_setup = colibri_t20_mcp2515_setup,
+ .oscillator_frequency = 16000000,
+ .power_enable = NULL,
+ .transceiver_enable = NULL
+};
+
+static struct spi_board_info mcp251x_board_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 10000000,
+ .modalias = "mcp2515",
+ .platform_data = &mcp251x_pdata,
+ },
+};
+
+static void __init colibri_t20_mcp2515_can_init(void)
+{
+ mcp251x_board_info[0].irq = gpio_to_irq(CAN_INTERRUPT_GPIO);
+ spi_register_board_info(mcp251x_board_info, ARRAY_SIZE(mcp251x_board_info));
+}
+#else /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+#define colibri_t20_mcp2515_can_init() do {} while (0)
+#endif /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+#define CAN_BASE_TEG 0x48000000 /* GMI_CS4_N */
+static struct resource colibri_can_resource[] = {
+ [0] = {
+ .start = CAN_BASE_TEG, /* address */
+ .end = CAN_BASE_TEG + 0xff, /* data */
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* interrupt assigned during initialisation */
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+ }
+};
+
+static struct sja1000_platform_data colibri_can_platdata = {
+ .osc_freq = 24000000,
+ .ocr = (OCR_MODE_NORMAL | OCR_TX0_PUSHPULL),
+ .cdr = CDR_CLK_OFF | /* Clock off (CLKOUT pin) */
+ CDR_CBP, /* CAN input comparator bypass */
+};
+
+static struct platform_device colibri_can_device = {
+ .name = "sja1000_platform",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(colibri_can_resource),
+ .resource = colibri_can_resource,
+ .dev = {
+ .platform_data = &colibri_can_platdata,
+ }
+};
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
+
+/* Clocks */
+static struct tegra_clk_init_table colibri_t30_clk_init_table[] __initdata = {
+ /* name parent rate enabled */
+ {"audio1", "i2s1_sync", 0, false},
+ {"audio2", "i2s2_sync", 0, false},
+ {"audio3", "i2s3_sync", 0, false},
+ {"blink", "clk_32k", 32768, true},
+ {"d_audio", "clk_m", 12000000, false},
+ {"dam0", "clk_m", 12000000, false},
+ {"dam1", "clk_m", 12000000, false},
+ {"dam2", "clk_m", 12000000, false},
+ {"hda", "pll_p", 108000000, false},
+ {"hda2codec_2x","pll_p", 48000000, false},
+ {"i2c1", "pll_p", 3200000, false},
+ {"i2c2", "pll_p", 3200000, false},
+ {"i2c3", "pll_p", 3200000, false},
+ {"i2c4", "pll_p", 3200000, false},
+ {"i2c5", "pll_p", 3200000, false},
+ {"i2s0", "pll_a_out0", 0, false},
+ {"i2s1", "pll_a_out0", 0, false},
+ {"i2s2", "pll_a_out0", 0, false},
+ {"i2s3", "pll_a_out0", 0, false},
+ {"nor", "pll_p", 86500000, true},
+ {"pll_a", NULL, 564480000, true},
+ {"pll_m", NULL, 0, false},
+ {"pwm", "pll_p", 3187500, false},
+ {"spdif_out", "pll_a_out0", 0, false},
+ {"vi", "pll_p", 0, false},
+ {"vi_sensor", "pll_p", 150000000, false},
+ {NULL, NULL, 0, 0},
+};
+
+/* GPIO */
+/* Pins in the following struct are configured as GPIO Inputs and
+ * accessible from userspace through /sys/class/gpio
+ * Pins which likely are used with one of their alternate functions
+ * are commented out.
+ * Refer to the TRM, chapters 'Multi-Prupose Io Pins' and 'GPIO Controller'
+ */
+static struct gpio colibri_t30_gpios[] = {
+// {TEGRA_GPIO_PA2, GPIOF_IN, "SODIMM pin 186"},
+// {TEGRA_GPIO_PA3, GPIOF_IN, "SODIMM pin 184"},
+ {TEGRA_GPIO_PB2, GPIOF_IN, "SODIMM pin 154"},
+#if !defined(CONFIG_SPI_GPIO) && !defined(CONFIG_SPI_GPIO_MODULE)
+//conflicts with MECS Tellurium xPOD2 SSPCLK2
+// {TEGRA_GPIO_PB6, GPIOF_IN, "SODIMM pin 55"},
+#endif
+#ifndef MECS_TELLURIUM_XPOD2
+//conflicts with MECS Tellurium xPOD2 SSPFRM2
+// {TEGRA_GPIO_PB7, GPIOF_IN, "SODIMM pin 63"},
+#endif
+#ifndef COLIBRI_T30_VI
+ {TEGRA_GPIO_PC1, GPIOF_IN, "SODIMM pin 81"},
+#endif
+ {TEGRA_GPIO_PI3, GPIOF_IN, "SODIMM pin 130"},
+ {TEGRA_GPIO_PI6, GPIOF_IN, "SODIMM pin 132"},
+ //{TEGRA_GPIO_PJ0, GPIOF_IN, "SODIMM pin 126"},
+ //{TEGRA_GPIO_PJ2, GPIOF_IN, "SODIMM pin 128"},
+//conflicts with GMI_ADV_N used for multiplexed address/data bus
+// {TEGRA_GPIO_PK0, GPIOF_IN, "SODIMM pin 150"},
+// {TEGRA_GPIO_PK1, GPIOF_IN, "SODIMM pin 152"},
+#ifndef CONFIG_KEYBOARD_GPIO
+//conflicts with menu key
+// {TEGRA_GPIO_PK6, GPIOF_IN, "SODIMM pin 135"},
+#endif
+// {TEGRA_GPIO_PN0, GPIOF_IN, "SODIMM pin 174"},
+// {TEGRA_GPIO_PN1, GPIOF_IN, "SODIMM pin 176"},
+// {TEGRA_GPIO_PN2, GPIOF_IN, "SODIMM pin 178"},
+// {TEGRA_GPIO_PN3, GPIOF_IN, "SODIMM pin 180"},
+// {TEGRA_GPIO_PN4, GPIOF_IN, "SODIMM pin 160"},
+// {TEGRA_GPIO_PN5, GPIOF_IN, "SODIMM pin 158"},
+ {TEGRA_GPIO_PN6, GPIOF_IN, "SODIMM pin 162"},
+//conflicts with ADDRESS13
+// {TEGRA_GPIO_PP4, GPIOF_IN, "SODIMM pin 120"},
+//conflicts with ADDRESS14
+// {TEGRA_GPIO_PP5, GPIOF_IN, "SODIMM pin 122"},
+//conflicts with ADDRESS15
+// {TEGRA_GPIO_PP6, GPIOF_IN, "SODIMM pin 124"},
+// {TEGRA_GPIO_PP7, GPIOF_IN, "SODIMM pin 188"},
+#if !defined(IRIS) && !defined(CONFIG_CAN_MCP251X) && \
+ !defined(CONFIG_CAN_MCP251X_MODULE) && \
+ !defined(CONFIG_CAN_SJA1000) && \
+ !defined(CONFIG_CAN_SJA1000_MODULE)
+//conflicts with CAN interrupt on Colibri Evaluation Board and MECS Tellurium
+//xPOD1 CAN
+//conflicts with DAC_PSAVE# on Iris
+ {TEGRA_GPIO_PS0, GPIOF_IN, "SODIMM pin 73"},
+#endif
+#ifndef CONFIG_KEYBOARD_GPIO
+//conflicts with back key
+ {TEGRA_GPIO_PT5, GPIOF_IN, "SOD-133, Iris X16-14"},
+//conflicts with home key
+ {TEGRA_GPIO_PT6, GPIOF_IN, "SODIMM pin 127"},
+//conflicts with power key (WAKE1)
+ {TEGRA_GPIO_PV1, GPIOF_IN, "SODI-45, Iris X16-20"},
+#endif
+#ifndef COLIBRI_T30_VI
+ {TEGRA_GPIO_PW5, GPIOF_IN, "SODIMM pin 75"},
+ //conflicts with BL_ON
+ //{TEGRA_GPIO_PV2, GPIOF_IN, "SODIMM pin 71"},
+ {TEGRA_GPIO_PV3, GPIOF_IN, "SODI-85, Iris X16-18"},
+#endif
+//conflicts with ADDRESS12
+// {TEGRA_GPIO_PU6, GPIOF_IN, "SODIMM pin 118"},
+//multiplexed LCD_D21
+// {TEGRA_GPIO_PX0, GPIOF_IN, "SODIMM pin 142"},
+//multiplexed LCD_D20
+// {TEGRA_GPIO_PX1, GPIOF_IN, "SODIMM pin 140"},
+//multiplexed LCD_D19
+// {TEGRA_GPIO_PX2, GPIOF_IN, "SODIMM pin 138"},
+//multiplexed LCD_D18
+// {TEGRA_GPIO_PX3, GPIOF_IN, "SODIMM pin 136"},
+ {TEGRA_GPIO_PX4, GPIOF_IN, "SODIMM pin 134"},
+ {TEGRA_GPIO_PX6, GPIOF_IN, "102, I X13 ForceOFF#"},
+ {TEGRA_GPIO_PX7, GPIOF_IN, "104, I X14 ForceOFF#"},
+#ifndef COLIBRI_T30_VI
+// {TEGRA_GPIO_PY4, GPIOF_IN, "SODI-97, Iris X16-17"},
+// {TEGRA_GPIO_PY5, GPIOF_IN, "SODI-79, Iris X16-19"},
+// {TEGRA_GPIO_PY6, GPIOF_IN, "SODI-103, Iris X16-15"},
+// {TEGRA_GPIO_PY7, GPIOF_IN, "SODI-101, Iris X16-16"},
+// {TEGRA_GPIO_PZ0, GPIOF_IN, "SODI-96"},
+// {TEGRA_GPIO_PZ1, GPIOF_IN, "SODI-98, Iris X16-13"},
+#endif
+// {TEGRA_GPIO_PZ2, GPIOF_IN, "SODIMM pin 156"},
+// {TEGRA_GPIO_PZ4, GPIOF_IN, "SODIMM pin 164"},
+ {TEGRA_GPIO_PBB4, GPIOF_IN, "SODIMM pin 166"},
+ {TEGRA_GPIO_PBB5, GPIOF_IN, "SODIMM pin 168"},
+ {TEGRA_GPIO_PBB6, GPIOF_IN, "SODIMM pin 170"},
+ {TEGRA_GPIO_PBB7, GPIOF_IN, "SODIMM pin 172"},
+#ifndef COLIBRI_T30_VI
+// {TEGRA_GPIO_PCC2, GPIOF_IN, "SODIMM pin 77"},
+ {TEGRA_GPIO_PCC7, GPIOF_IN, "SODIMM pin 94"},
+#endif
+#ifndef CONFIG_KEYBOARD_GPIO
+//conflicts with volume down key
+ {TEGRA_GPIO_PCC6, GPIOF_IN, "SODIMM pin 24"},
+//conflicts with volume up key
+ {TEGRA_GPIO_PDD7, GPIOF_IN, "SODIMM pin 22"},
+#endif
+#ifndef COLIBRI_T30_VI
+ {TEGRA_GPIO_PDD5, GPIOF_IN, "SODIMM pin 69"},
+ {TEGRA_GPIO_PDD6, GPIOF_IN, "SODIMM pin 65"},
+#endif
+
+};
+
+static void colibri_t30_gpio_init(void)
+{
+ int i = 0;
+ int length = sizeof(colibri_t30_gpios) / sizeof(struct gpio);
+ int err = 0;
+
+ for (i = 0; i < length; i++) {
+ err = gpio_request_one(colibri_t30_gpios[i].gpio,
+ colibri_t30_gpios[i].flags,
+ colibri_t30_gpios[i].label);
+
+ if (err) {
+ pr_warning("gpio_request(%s) failed, err = %d",
+ colibri_t30_gpios[i].label, err);
+ } else {
+ gpio_export(colibri_t30_gpios[i].gpio, true);
+ }
+ }
+}
+
+/*
+ * Fusion touch screen GPIOs (using Toradex display/touch adapater)
+ * Iris X16-38, SODIMM pin 28 (PWM B), pen down interrupt
+ * Iris X16-39, SODIMM pin 30 (PWM C), reset
+ * gpio_request muxes the GPIO function automatically, we only have to make
+ * sure input/output muxing is done here...
+ */
+static struct fusion_f0710a_init_data colibri_fusion_pdata = {
+ .pinmux_fusion_pins = NULL,
+ .gpio_int = TEGRA_GPIO_PB5, /* SO-DIMM 28: Pen down interrupt */
+ .gpio_reset = TEGRA_GPIO_PA6, /* SO-DIMM 30: Reset interrupt */
+};
+
+/* I2C */
+
+/* Make sure that the pinmuxing enable the 'open drain' feature for pins used
+ for I2C */
+
+/* GEN1_I2C: I2C_SDA/SCL on SODIMM pin 194/196 (e.g. RTC on carrier board) */
+static struct i2c_board_info colibri_t30_i2c_bus1_board_info[] __initdata = {
+ {
+ /* M41T0M6 real time clock on Iris carrier board */
+ I2C_BOARD_INFO("rtc-ds1307", 0x68),
+ .type = "m41t00",
+ },
+ {
+ /* TouchRevolution Fusion 7 and 10 multi-touch controller */
+ I2C_BOARD_INFO("fusion_F0710A", 0x10),
+ .platform_data = &colibri_fusion_pdata,
+ },
+};
+
+static struct tegra_i2c_platform_data colibri_t30_i2c1_platform_data = {
+ .adapter_nr = 0,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {400000, 0},
+ .bus_count = 1,
+ .scl_gpio = {I2C_SCL, 0},
+ .sda_gpio = {I2C_SDA, 0},
+ .slave_addr = 0x00FC,
+};
+
+/* GEN2_I2C: unused */
+
+/* DDC_CLOCK/DATA on X3 pin 15/16 (e.g. display EDID) */
+static struct tegra_i2c_platform_data colibri_t30_i2c4_platform_data = {
+ .adapter_nr = 3,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {10000, 10000},
+ .bus_count = 1,
+ .scl_gpio = {DDC_SCL, 0},
+ .sda_gpio = {DDC_SDA, 0},
+ .slave_addr = 0x00FC,
+};
+
+/* PWR_I2C: power I2C to audio codec, PMIC, temperature sensor and touch screen
+ controller */
+
+/* STMPE811 touch screen controller */
+static struct stmpe_ts_platform_data stmpe811_ts_data = {
+ .adc_freq = 1, /* 3.25 MHz ADC clock speed */
+ .ave_ctrl = 3, /* 8 sample average control */
+ .fraction_z = 7, /* 7 length fractional part in z */
+ .i_drive = 1, /* 50 mA typical 80 mA max touchscreen
+ drivers current limit value */
+ .mod_12b = 1, /* 12-bit ADC */
+ .ref_sel = 0, /* internal ADC reference */
+ .sample_time = 4, /* ADC converstion time: 80 clocks */
+ .settling = 3, /* 1 ms panel driver settling time */
+ .touch_det_delay = 5, /* 5 ms touch detect interrupt delay */
+};
+
+/* STMPE811 ADC controller */
+static struct stmpe_adc_platform_data stmpe811_adc_data = {
+ .sample_time = 4, /* ADC converstion time: 80 clocks */
+ .mod_12b = 1, /* 12-bit ADC */
+ .ref_sel = 0, /* internal ADC reference */
+ .adc_freq = 1, /* 3.25 MHz ADC clock speed */
+};
+
+static struct stmpe_platform_data stmpe811_data = {
+ .blocks = STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC,
+ .id = 1,
+ .irq_base = STMPE811_IRQ_BASE,
+ .irq_trigger = IRQF_TRIGGER_FALLING,
+ .ts = &stmpe811_ts_data,
+ .adc = &stmpe811_adc_data,
+};
+
+static void lm95245_probe_callback(struct device *dev);
+
+static struct lm95245_platform_data colibri_t30_lm95245_pdata = {
+ .enable_os_pin = true,
+ .probe_callback = lm95245_probe_callback,
+};
+
+static struct i2c_board_info colibri_t30_i2c_bus5_board_info[] __initdata = {
+ {
+ /* SGTL5000 audio codec */
+ I2C_BOARD_INFO("sgtl5000", 0x0a),
+ },
+ {
+ /* STMPE811 touch screen controller */
+ I2C_BOARD_INFO("stmpe", 0x41),
+ .flags = I2C_CLIENT_WAKE,
+ .platform_data = &stmpe811_data,
+ .type = "stmpe811",
+ },
+ {
+ /* LM95245 temperature sensor
+ Note: OVERT_N directly connected to PMIC PWRDN */
+ I2C_BOARD_INFO("lm95245", 0x4c),
+ .platform_data = &colibri_t30_lm95245_pdata,
+ },
+};
+
+static struct tegra_i2c_platform_data colibri_t30_i2c5_platform_data = {
+ .adapter_nr = 4,
+ .arb_recovery = arb_lost_recovery,
+ .bus_clk_rate = {400000, 0},
+ .bus_count = 1,
+ .scl_gpio = {PWR_I2C_SCL, 0},
+ .sda_gpio = {PWR_I2C_SDA, 0},
+};
+
+static void __init colibri_t30_i2c_init(void)
+{
+ tegra_i2c_device1.dev.platform_data = &colibri_t30_i2c1_platform_data;
+ tegra_i2c_device4.dev.platform_data = &colibri_t30_i2c4_platform_data;
+ tegra_i2c_device5.dev.platform_data = &colibri_t30_i2c5_platform_data;
+
+ platform_device_register(&tegra_i2c_device1);
+ platform_device_register(&tegra_i2c_device4);
+ platform_device_register(&tegra_i2c_device5);
+
+ i2c_register_board_info(0, colibri_t30_i2c_bus1_board_info,
+ ARRAY_SIZE(colibri_t30_i2c_bus1_board_info));
+
+ /* enable touch interrupt GPIO */
+ gpio_request(TOUCH_PEN_INT, "TOUCH_PEN_INT");
+ gpio_direction_input(TOUCH_PEN_INT);
+
+ colibri_t30_i2c_bus5_board_info[1].irq = gpio_to_irq(TOUCH_PEN_INT);
+ i2c_register_board_info(4, colibri_t30_i2c_bus5_board_info,
+ ARRAY_SIZE(colibri_t30_i2c_bus5_board_info));
+}
+
+/* Keys
+ * Note: active-low means pull-ups required on carrier board resp. via
+ * pin-muxing
+ * Note2: power-key active-high due to EvalBoard v3.1a having 100 K pull-down
+ * on SODIMM pin 45
+ * Note3: Wake keys need to be supported by hardware, see wakeups-t3.h
+ */
+
+#ifdef CONFIG_KEYBOARD_GPIO
+#define GPIO_KEY(_id, _gpio, _lowactive, _iswake) \
+ { \
+ .code = _id, \
+ .gpio = TEGRA_GPIO_##_gpio, \
+ .active_low = _lowactive, \
+ .desc = #_id, \
+ .type = EV_KEY, \
+ .wakeup = _iswake, \
+ .debounce_interval = 10, \
+ }
+
+/* Note: Only wake-able gpios can be used as wakeup keys */
+static struct gpio_keys_button colibri_t30_keys[] = {
+#ifndef COLIBRI_T30_VI
+ GPIO_KEY(KEY_FIND, PCC2, 1, 0), /* SODIMM pin 77 */
+#endif
+ GPIO_KEY(KEY_HOME, PT6, 1, 0), /* SODIMM pin 127 */
+ GPIO_KEY(KEY_BACK, PT5, 1, 0), /* SODIMM pin 133,
+ Iris X16-14 */
+ GPIO_KEY(KEY_VOLUMEUP, PDD7, 1, 0), /* SODIMM pin 22 */
+ GPIO_KEY(KEY_VOLUMEDOWN, PCC6, 1, 0), /* SODIMM pin 24 */
+ GPIO_KEY(KEY_POWER, PV1, 0, 1), /* SODIMM pin 45,
+ Iris X16-20 */
+ GPIO_KEY(KEY_MENU, PK6, 1, 0), /* SODIMM pin 135 */
+};
+
+static struct gpio_keys_platform_data colibri_t30_keys_platform_data = {
+ .buttons = colibri_t30_keys,
+ .nbuttons = ARRAY_SIZE(colibri_t30_keys),
+};
+
+static struct platform_device colibri_t30_keys_device = {
+ .name = "gpio-keys",
+ .id = 0,
+ .dev = {
+ .platform_data = &colibri_t30_keys_platform_data,
+ },
+};
+#endif /* CONFIG_KEYBOARD_GPIO */
+
+/* MMC/SD */
+
+#ifndef COLIBRI_T30_SDMMC4B
+static struct tegra_sdhci_platform_data colibri_t30_emmc_platform_data = {
+ .cd_gpio = -1,
+ .ddr_clk_limit = 52000000,
+ .is_8bit = 1,
+ .mmc_data = {
+ .built_in = 1,
+ },
+ .power_gpio = -1,
+ .tap_delay = 0x0f,
+ .wp_gpio = -1,
+};
+#endif /* COLIBRI_T30_SDMMC4B */
+
+static struct tegra_sdhci_platform_data colibri_t30_sdcard_platform_data = {
+ .cd_gpio = MMC_CD,
+ .ddr_clk_limit = 52000000,
+ .is_8bit = 0,
+ .power_gpio = -1,
+ .tap_delay = 0x0f,
+ .wp_gpio = -1,
+};
+
+static void __init colibri_t30_sdhci_init(void)
+{
+ /* register eMMC first */
+ tegra_sdhci_device4.dev.platform_data =
+#ifdef COLIBRI_T30_SDMMC4B
+ &colibri_t30_sdcard_platform_data;
+#else
+ &colibri_t30_emmc_platform_data;
+#endif
+ platform_device_register(&tegra_sdhci_device4);
+
+#ifndef COLIBRI_T30_SDMMC4B
+ tegra_sdhci_device2.dev.platform_data =
+ &colibri_t30_sdcard_platform_data;
+ platform_device_register(&tegra_sdhci_device2);
+#endif
+}
+
+/* PWM LEDs */
+static struct led_pwm tegra_leds_pwm[] = {
+ {
+ .name = "PWM<B>",
+ .pwm_id = 1,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+ {
+ .name = "PWM<C>",
+ .pwm_id = 2,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+ {
+ .name = "PWM<D>",
+ .pwm_id = 3,
+ .max_brightness = 255,
+ .pwm_period_ns = 19600,
+ },
+};
+
+static struct led_pwm_platform_data tegra_leds_pwm_data = {
+ .num_leds = ARRAY_SIZE(tegra_leds_pwm),
+ .leds = tegra_leds_pwm,
+};
+
+static struct platform_device tegra_led_pwm_device = {
+ .name = "leds_pwm",
+ .id = -1,
+ .dev = {
+ .platform_data = &tegra_leds_pwm_data,
+ },
+};
+
+/* RTC */
+
+#ifdef CONFIG_RTC_DRV_TEGRA
+static struct resource tegra_rtc_resources[] = {
+ [0] = {
+ .start = TEGRA_RTC_BASE,
+ .end = TEGRA_RTC_BASE + TEGRA_RTC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = INT_RTC,
+ .end = INT_RTC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tegra_rtc_device = {
+ .name = "tegra_rtc",
+ .id = -1,
+ .resource = tegra_rtc_resources,
+ .num_resources = ARRAY_SIZE(tegra_rtc_resources),
+};
+#endif /* CONFIG_RTC_DRV_TEGRA */
+
+/* SPI */
+
+#if defined(CONFIG_SPI_TEGRA) && defined(CONFIG_SPI_SPIDEV)
+static struct spi_board_info tegra_spi_devices[] __initdata = {
+ {
+ .bus_num = 0, /* SPI1: Colibri SSP */
+#if !defined(CONFIG_CAN_MCP251X) && !defined(CONFIG_CAN_MCP251X_MODULE)
+ .chip_select = 0,
+#else /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */
+ .chip_select = 1,
+#endif /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */
+ .irq = 0,
+ .max_speed_hz = 50000000,
+ .modalias = "spidev",
+ .mode = SPI_MODE_0,
+ .platform_data = NULL,
+ },
+};
+
+static void __init colibri_t30_register_spidev(void)
+{
+ spi_register_board_info(tegra_spi_devices,
+ ARRAY_SIZE(tegra_spi_devices));
+}
+#else /* CONFIG_SPI_TEGRA && CONFIG_SPI_SPIDEV */
+#define colibri_t30_register_spidev() do {} while (0)
+#endif /* CONFIG_SPI_TEGRA && CONFIG_SPI_SPIDEV */
+
+static struct platform_device *colibri_t30_spi_devices[] __initdata = {
+ &tegra_spi_device1,
+};
+
+static struct spi_clk_parent spi_parent_clk[] = {
+ [0] = {.name = "pll_p"},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
+ [1] = {.name = "pll_m"},
+ [2] = {.name = "clk_m"},
+#else /* !CONFIG_TEGRA_PLLM_RESTRICTED */
+ [1] = {.name = "clk_m"},
+#endif /* !CONFIG_TEGRA_PLLM_RESTRICTED */
+};
+
+static struct tegra_spi_platform_data colibri_t30_spi_pdata = {
+ .is_dma_based = true,
+ .max_dma_buffer = 16 * 1024,
+ .is_clkon_always = false,
+ .max_rate = 100000000,
+};
+
+static void __init colibri_t30_spi_init(void)
+{
+ int i;
+ struct clk *c;
+
+ for (i = 0; i < ARRAY_SIZE(spi_parent_clk); ++i) {
+ c = tegra_get_clock_by_name(spi_parent_clk[i].name);
+ if (IS_ERR_OR_NULL(c)) {
+ pr_err("Not able to get the clock for %s\n",
+ spi_parent_clk[i].name);
+ continue;
+ }
+ spi_parent_clk[i].parent_clk = c;
+ spi_parent_clk[i].fixed_clk_rate = clk_get_rate(c);
+ }
+ colibri_t30_spi_pdata.parent_clk_list = spi_parent_clk;
+ colibri_t30_spi_pdata.parent_clk_count = ARRAY_SIZE(spi_parent_clk);
+ tegra_spi_device1.dev.platform_data = &colibri_t30_spi_pdata;
+ platform_add_devices(colibri_t30_spi_devices,
+ ARRAY_SIZE(colibri_t30_spi_devices));
+}
+
+/* Thermal throttling */
+
+static void *colibri_t30_alert_data;
+static void (*colibri_t30_alert_func)(void *);
+static int colibri_t30_low_edge = 0;
+static int colibri_t30_low_hysteresis = 3000;
+static int colibri_t30_low_limit = 0;
+static struct device *lm95245_device = NULL;
+static int thermd_alert_irq_disabled = 0;
+struct work_struct thermd_alert_work;
+struct workqueue_struct *thermd_alert_workqueue;
+
+static struct balanced_throttle throttle_list[] = {
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ {
+ .id = BALANCED_THROTTLE_ID_TJ,
+ .throt_tab_size = 10,
+ .throt_tab = {
+ { 0, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 640000, 1000 },
+ { 760000, 1000 },
+ { 760000, 1050 },
+ {1000000, 1050 },
+ {1000000, 1100 },
+ },
+ },
+#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ {
+ .id = BALANCED_THROTTLE_ID_SKIN,
+ .throt_tab_size = 6,
+ .throt_tab = {
+ { 640000, 1200 },
+ { 640000, 1200 },
+ { 760000, 1200 },
+ { 760000, 1200 },
+ {1000000, 1200 },
+ {1000000, 1200 },
+ },
+ },
+#endif /* CONFIG_TEGRA_SKIN_THROTTLE */
+};
+
+/* All units are in millicelsius */
+static struct tegra_thermal_data thermal_data = {
+ .shutdown_device_id = THERMAL_DEVICE_ID_NCT_EXT,
+ .temp_shutdown = 115000,
+
+#if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE)
+ .throttle_edp_device_id = THERMAL_DEVICE_ID_NCT_EXT,
+#endif
+#ifdef CONFIG_TEGRA_EDP_LIMITS
+ .edp_offset = TDIODE_OFFSET, /* edp based on tdiode */
+ .hysteresis_edp = 3000,
+#endif
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+ .temp_throttle = 85000,
+ .tc1 = 0,
+ .tc2 = 1,
+ .passive_delay = 2000,
+#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ .skin_device_id = THERMAL_DEVICE_ID_SKIN,
+ .temp_throttle_skin = 43000,
+ .tc1_skin = 0,
+ .tc2_skin = 1,
+ .passive_delay_skin = 5000,
+
+ .skin_temp_offset = 9793,
+ .skin_period = 1100,
+ .skin_devs_size = 2,
+ .skin_devs = {
+ {
+ THERMAL_DEVICE_ID_NCT_EXT,
+ {
+ 2, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 0,
+ 1, 1, 0, 0,
+ 0, 0, -1, -7
+ }
+ },
+ {
+ THERMAL_DEVICE_ID_NCT_INT,
+ {
+ -11, -7, -5, -3,
+ -3, -2, -1, 0,
+ 0, 0, 1, 1,
+ 1, 2, 2, 3,
+ 4, 6, 11, 18
+ }
+ },
+ },
+#endif /* CONFIG_TEGRA_SKIN_THROTTLE */
+};
+
+/* Over-temperature shutdown OS aka high limit GPIO pin interrupt handler */
+static irqreturn_t thermd_alert_irq(int irq, void *data)
+{
+ disable_irq_nosync(irq);
+ thermd_alert_irq_disabled = 1;
+ queue_work(thermd_alert_workqueue, &thermd_alert_work);
+
+ return IRQ_HANDLED;
+}
+
+/* Gets both entered by THERMD_ALERT GPIO interrupt as well as re-scheduled. */
+static void thermd_alert_work_func(struct work_struct *work)
+{
+ int temp = 0;
+
+ lm95245_get_remote_temp(lm95245_device, &temp);
+
+ /* This emulates NCT1008 low limit behaviour */
+ if (!colibri_t30_low_edge && temp <= colibri_t30_low_limit) {
+ colibri_t30_alert_func(colibri_t30_alert_data);
+ colibri_t30_low_edge = 1;
+ } else if (colibri_t30_low_edge && temp > colibri_t30_low_limit +
+ colibri_t30_low_hysteresis) {
+ colibri_t30_low_edge = 0;
+ }
+
+ /* Avoid unbalanced enable for IRQ 367 */
+ if (thermd_alert_irq_disabled) {
+ colibri_t30_alert_func(colibri_t30_alert_data);
+ thermd_alert_irq_disabled = 0;
+ enable_irq(gpio_to_irq(THERMD_ALERT));
+ }
+
+ /* Keep re-scheduling */
+ msleep(2000);
+ queue_work(thermd_alert_workqueue, &thermd_alert_work);
+}
+
+static int lm95245_get_temp(void *_data, long *temp)
+{
+ struct device *lm95245_device = _data;
+ int lm95245_temp = 0;
+ lm95245_get_remote_temp(lm95245_device, &lm95245_temp);
+ *temp = lm95245_temp;
+ return 0;
+}
+
+static int lm95245_get_temp_low(void *_data, long *temp)
+{
+ *temp = 0;
+ return 0;
+}
+
+/* Our temperature sensor only allows triggering an interrupt on over-
+ temperature shutdown aka the high limit we therefore need to setup a
+ workqueue to catch leaving the low limit. */
+static int lm95245_set_limits(void *_data,
+ long lo_limit_milli,
+ long hi_limit_milli)
+{
+ struct device *lm95245_device = _data;
+ colibri_t30_low_limit = lo_limit_milli;
+ if (lm95245_device) lm95245_set_remote_os_limit(lm95245_device,
+ hi_limit_milli);
+ return 0;
+}
+
+static int lm95245_set_alert(void *_data,
+ void (*alert_func)(void *),
+ void *alert_data)
+{
+ lm95245_device = _data;
+ colibri_t30_alert_func = alert_func;
+ colibri_t30_alert_data = alert_data;
+ return 0;
+}
+
+static int lm95245_set_shutdown_temp(void *_data, long shutdown_temp)
+{
+ struct device *lm95245_device = _data;
+ if (lm95245_device) lm95245_set_remote_critical_limit(lm95245_device,
+ shutdown_temp);
+ return 0;
+}
+
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+/* Internal aka local board/case temp */
+static int lm95245_get_itemp(void *dev_data, long *temp)
+{
+ struct device *lm95245_device = dev_data;
+ int lm95245_temp = 0;
+ lm95245_get_local_temp(lm95245_device, &lm95245_temp);
+ *temp = lm95245_temp;
+ return 0;
+}
+#endif /* CONFIG_TEGRA_SKIN_THROTTLE */
+
+static void lm95245_probe_callback(struct device *dev)
+{
+ struct tegra_thermal_device *lm95245_remote;
+
+ lm95245_remote = kzalloc(sizeof(struct tegra_thermal_device),
+ GFP_KERNEL);
+ if (!lm95245_remote) {
+ pr_err("unable to allocate thermal device\n");
+ return;
+ }
+
+ lm95245_remote->name = "lm95245_remote";
+ lm95245_remote->id = THERMAL_DEVICE_ID_NCT_EXT;
+ lm95245_remote->data = dev;
+ lm95245_remote->offset = TDIODE_OFFSET;
+ lm95245_remote->get_temp = lm95245_get_temp;
+ lm95245_remote->get_temp_low = lm95245_get_temp_low;
+ lm95245_remote->set_limits = lm95245_set_limits;
+ lm95245_remote->set_alert = lm95245_set_alert;
+ lm95245_remote->set_shutdown_temp = lm95245_set_shutdown_temp;
+
+ tegra_thermal_device_register(lm95245_remote);
+
+#ifdef CONFIG_TEGRA_SKIN_THROTTLE
+ {
+ struct tegra_thermal_device *lm95245_local;
+ lm95245_local = kzalloc(sizeof(struct tegra_thermal_device),
+ GFP_KERNEL);
+ if (!lm95245_local) {
+ kfree(lm95245_local);
+ pr_err("unable to allocate thermal device\n");
+ return;
+ }
+
+ lm95245_local->name = "lm95245_local";
+ lm95245_local->id = THERMAL_DEVICE_ID_NCT_INT;
+ lm95245_local->data = dev;
+ lm95245_local->get_temp = lm95245_get_itemp;
+
+ tegra_thermal_device_register(lm95245_local);
+ }
+#endif /* CONFIG_TEGRA_SKIN_THROTTLE */
+
+ if (request_irq(gpio_to_irq(THERMD_ALERT), thermd_alert_irq,
+ IRQF_TRIGGER_LOW, "THERMD_ALERT", NULL))
+ pr_err("%s: unable to register THERMD_ALERT interrupt\n",
+ __func__);
+
+ //initalize the local temp limit
+ if(dev)
+ lm95245_set_local_shared_os__critical_limit(dev, TCRIT_LOCAL);
+}
+
+static void colibri_t30_thermd_alert_init(void)
+{
+ gpio_request(THERMD_ALERT, "THERMD_ALERT");
+ gpio_direction_input(THERMD_ALERT);
+
+ thermd_alert_workqueue = create_singlethread_workqueue("THERMD_ALERT");
+
+ INIT_WORK(&thermd_alert_work, thermd_alert_work_func);
+}
+
+/* UART */
+
+static struct platform_device *colibri_t30_uart_devices[] __initdata = {
+ &tegra_uarta_device, /* Colibri FFUART */
+ &tegra_uartd_device, /* Colibri BTUART */
+ &tegra_uartb_device, /* Colibri STDUART */
+};
+
+static struct uart_clk_parent uart_parent_clk[] = {
+ [0] = {.name = "clk_m"},
+ [1] = {.name = "pll_p"},
+#ifndef CONFIG_TEGRA_PLLM_RESTRICTED
+ [2] = {.name = "pll_m"},
+#endif
+};
+
+static struct tegra_uart_platform_data colibri_t30_uart_pdata;
+
+static void __init uart_debug_init(void)
+{
+ int debug_port_id;
+
+ debug_port_id = get_tegra_uart_debug_port_id();
+ if (debug_port_id < 0) {
+ debug_port_id = 0;
+ }
+
+ switch (debug_port_id) {
+ case 0:
+ /* UARTA is the debug port. */
+ pr_info("Selecting UARTA as the debug console\n");
+ colibri_t30_uart_devices[0] = &debug_uarta_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uarta");
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uarta_device.dev.platform_data))->mapbase;
+ break;
+
+ case 1:
+ /* UARTB is the debug port. */
+ pr_info("Selecting UARTB as the debug console\n");
+ colibri_t30_uart_devices[2] = &debug_uartb_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uartb");
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uartb_device.dev.platform_data))->mapbase;
+ break;
+
+ case 3:
+ /* UARTD is the debug port. */
+ pr_info("Selecting UARTD as the debug console\n");
+ colibri_t30_uart_devices[1] = &debug_uartd_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uartd");
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uartd_device.dev.platform_data))->mapbase;
+ break;
+
+ default:
+ pr_info("The debug console id %d is invalid, Assuming UARTA",
+ debug_port_id);
+ colibri_t30_uart_devices[0] = &debug_uarta_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uarta");
+ debug_uart_port_base = ((struct plat_serial8250_port *)(
+ debug_uarta_device.dev.platform_data))->mapbase;
+ break;
+ }
+ return;
+}
+
+static void __init colibri_t30_uart_init(void)
+{
+ struct clk *c;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(uart_parent_clk); ++i) {
+ c = tegra_get_clock_by_name(uart_parent_clk[i].name);
+ if (IS_ERR_OR_NULL(c)) {
+ pr_err("Not able to get the clock for %s\n",
+ uart_parent_clk[i].name);
+ continue;
+ }
+ uart_parent_clk[i].parent_clk = c;
+ uart_parent_clk[i].fixed_clk_rate = clk_get_rate(c);
+ }
+ colibri_t30_uart_pdata.parent_clk_list = uart_parent_clk;
+ colibri_t30_uart_pdata.parent_clk_count = ARRAY_SIZE(uart_parent_clk);
+ tegra_uarta_device.dev.platform_data = &colibri_t30_uart_pdata;
+ tegra_uartb_device.dev.platform_data = &colibri_t30_uart_pdata;
+ tegra_uartd_device.dev.platform_data = &colibri_t30_uart_pdata;
+
+ /* Register low speed only if it is selected */
+ if (!is_tegra_debug_uartport_hs()) {
+ uart_debug_init();
+ /* Clock enable for the debug channel */
+ if (!IS_ERR_OR_NULL(debug_uart_clk)) {
+ pr_info("The debug console clock name is %s\n",
+ debug_uart_clk->name);
+ c = tegra_get_clock_by_name("pll_p");
+ if (IS_ERR_OR_NULL(c))
+ pr_err("Not getting the parent clock pll_p\n");
+ else
+ clk_set_parent(debug_uart_clk, c);
+
+ clk_enable(debug_uart_clk);
+ clk_set_rate(debug_uart_clk, clk_get_rate(c));
+ } else {
+ pr_err("Not getting the clock %s for debug console\n",
+ debug_uart_clk->name);
+ }
+ }
+
+ platform_add_devices(colibri_t30_uart_devices,
+ ARRAY_SIZE(colibri_t30_uart_devices));
+}
+
+/* USB */
+
+//TODO: overcurrent
+
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .has_hostpc = true,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = true,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 8,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+ .u_data.dev = {
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
+ .vbus_gpio = -1,
+ .vbus_pmu_irq = 0,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+ .has_hostpc = true,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = true,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 15,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+ .u_data.host = {
+ .hot_plug = true,
+ .power_off_on_suspend = false,
+ .remote_wakeup_supported = true,
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ },
+};
+
+static void ehci2_utmi_platform_post_phy_on(void)
+{
+ /* enable VBUS */
+ gpio_set_value(LAN_V_BUS, 1);
+
+ /* reset */
+ gpio_set_value(LAN_RESET, 0);
+
+ udelay(5);
+
+ /* unreset */
+ gpio_set_value(LAN_RESET, 1);
+}
+
+static void ehci2_utmi_platform_pre_phy_off(void)
+{
+ /* disable VBUS */
+ gpio_set_value(LAN_V_BUS, 0);
+}
+
+static struct tegra_usb_phy_platform_ops ehci2_utmi_plat_ops = {
+ .post_phy_on = ehci2_utmi_platform_post_phy_on,
+ .pre_phy_off = ehci2_utmi_platform_pre_phy_off,
+};
+
+static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = {
+ .has_hostpc = true,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .ops = &ehci2_utmi_plat_ops,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = false,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 15,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+ .u_data.host = {
+ .hot_plug = false,
+ .power_off_on_suspend = true,
+ .remote_wakeup_supported = true,
+ .vbus_gpio = -1,
+ .vbus_reg = NULL,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
+ .has_hostpc = true,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .port_otg = false,
+ .u_cfg.utmi = {
+ .elastic_limit = 16,
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup = 8,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ },
+ .u_data.host = {
+ .hot_plug = true,
+ .power_off_on_suspend = false,
+ .remote_wakeup_supported = true,
+ .vbus_gpio = USBH_PEN,
+ .vbus_gpio_inverted = 1,
+ .vbus_reg = NULL,
+ },
+};
+
+#ifndef CONFIG_USB_TEGRA_OTG
+static struct platform_device *tegra_usb_otg_host_register(void)
+{
+ struct platform_device *pdev;
+ void *platform_data;
+ int val;
+
+ pdev = platform_device_alloc(tegra_ehci1_device.name,
+ tegra_ehci1_device.id);
+ if (!pdev)
+ return NULL;
+
+ val = platform_device_add_resources(pdev, tegra_ehci1_device.resource,
+ tegra_ehci1_device.num_resources);
+ if (val)
+ goto error;
+
+ pdev->dev.dma_mask = tegra_ehci1_device.dev.dma_mask;
+ pdev->dev.coherent_dma_mask = tegra_ehci1_device.dev.coherent_dma_mask;
+
+ platform_data = kmalloc(sizeof(struct tegra_usb_platform_data),
+ GFP_KERNEL);
+ if (!platform_data)
+ goto error;
+
+ memcpy(platform_data, &tegra_ehci1_utmi_pdata,
+ sizeof(struct tegra_usb_platform_data));
+ pdev->dev.platform_data = platform_data;
+
+ val = platform_device_add(pdev);
+ if (val)
+ goto error_add;
+
+ return pdev;
+
+error_add:
+ kfree(platform_data);
+error:
+ pr_err("%s: failed to add the host controller device\n", __func__);
+ platform_device_put(pdev);
+ return NULL;
+}
+
+static void tegra_usb_otg_host_unregister(struct platform_device *pdev)
+{
+ platform_device_unregister(pdev);
+}
+
+static struct colibri_otg_platform_data colibri_otg_pdata = {
+ .cable_detect_gpio = USBC_DET,
+ .host_register = &tegra_usb_otg_host_register,
+ .host_unregister = &tegra_usb_otg_host_unregister,
+};
+#else /* !CONFIG_USB_TEGRA_OTG */
+static struct tegra_usb_otg_data tegra_otg_pdata = {
+ .ehci_device = &tegra_ehci1_device,
+ .ehci_pdata = &tegra_ehci1_utmi_pdata,
+};
+#endif /* !CONFIG_USB_TEGRA_OTG */
+
+#ifndef CONFIG_USB_TEGRA_OTG
+struct platform_device colibri_otg_device = {
+ .name = "colibri-otg",
+ .id = -1,
+ .dev = {
+ .platform_data = &colibri_otg_pdata,
+ },
+};
+#endif /* !CONFIG_USB_TEGRA_OTG */
+
+static void colibri_t30_usb_init(void)
+{
+ gpio_request(LAN_V_BUS, "LAN_V_BUS");
+ gpio_direction_output(LAN_V_BUS, 0);
+ gpio_export(LAN_V_BUS, false);
+
+ gpio_request(LAN_RESET, "LAN_RESET");
+ gpio_direction_output(LAN_RESET, 0);
+ gpio_export(LAN_RESET, false);
+
+ /* OTG should be the first to be registered
+ EHCI instance 0: USB1_DP/N -> USBOTG_P/N */
+#ifndef CONFIG_USB_TEGRA_OTG
+ platform_device_register(&colibri_otg_device);
+#else /* !CONFIG_USB_TEGRA_OTG */
+ tegra_otg_device.dev.platform_data = &tegra_otg_pdata;
+ platform_device_register(&tegra_otg_device);
+#endif /* !CONFIG_USB_TEGRA_OTG */
+
+ /* setup the udc platform data */
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
+ platform_device_register(&tegra_udc_device);
+
+ /* EHCI instance 1: ASIX ETH */
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata;
+ platform_device_register(&tegra_ehci2_device);
+
+ /* EHCI instance 2: USB3_DP/N -> USBH1_P/N */
+ tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata;
+ platform_device_register(&tegra_ehci3_device);
+}
+
+/* W1, aka OWR, aka OneWire */
+
+#ifdef CONFIG_W1_MASTER_TEGRA
+struct tegra_w1_timings colibri_t30_w1_timings = {
+ .tsu = 1,
+ .trelease = 0xf,
+ .trdv = 0xf,
+ .tlow0 = 0x3c,
+ .tlow1 = 1,
+ .tslot = 0x77,
+
+ .tpdl = 0x78,
+ .tpdh = 0x1e,
+ .trstl = 0x1df,
+ .trsth = 0x1df,
+ .rdsclk = 0x7,
+ .psclk = 0x50,
+};
+
+struct tegra_w1_platform_data colibri_t30_w1_platform_data = {
+ .clk_id = "tegra_w1",
+ .timings = &colibri_t30_w1_timings,
+};
+#endif /* CONFIG_W1_MASTER_TEGRA */
+
+static struct platform_device *colibri_t30_devices[] __initdata = {
+ &tegra_pmu_device,
+#if defined(CONFIG_RTC_DRV_TEGRA)
+ &tegra_rtc_device,
+#endif
+#if defined(CONFIG_TEGRA_IOVMM_SMMU) || defined(CONFIG_TEGRA_IOMMU_SMMU)
+ &tegra_smmu_device,
+#endif
+ &tegra_wdt0_device,
+ &tegra_wdt1_device,
+ &tegra_wdt2_device,
+#if defined(CONFIG_TEGRA_AVP)
+ &tegra_avp_device,
+#endif
+#ifdef CONFIG_TEGRA_CAMERA
+ &tegra_camera,
+#endif
+#if defined(CONFIG_CRYPTO_DEV_TEGRA_SE)
+ &tegra_se_device,
+#endif
+#if defined(CONFIG_CRYPTO_DEV_TEGRA_AES)
+ &tegra_aes_device,
+#endif
+ &tegra_ahub_device,
+ &tegra_dam_device0,
+ &tegra_dam_device1,
+ &tegra_dam_device2,
+ &tegra_i2s_device2,
+ &tegra_spdif_device,
+ &spdif_dit_device,
+ &tegra_pcm_device,
+ &colibri_t30_audio_sgtl5000_device,
+#ifdef CONFIG_ANDROID
+ &tegra_hda_device,
+#endif
+ &tegra_cec_device,
+#ifdef CONFIG_KEYBOARD_GPIO
+ &colibri_t30_keys_device,
+#endif
+ &tegra_led_pwm_device,
+ &tegra_pwfm1_device,
+ &tegra_pwfm2_device,
+ &tegra_pwfm3_device,
+#ifdef CONFIG_W1_MASTER_TEGRA
+ &tegra_w1_device,
+#endif
+};
+
+static void __init colibri_t30_init(void)
+{
+ tegra_thermal_init(&thermal_data,
+ throttle_list,
+ ARRAY_SIZE(throttle_list));
+ tegra_clk_init_from_table(colibri_t30_clk_init_table);
+ colibri_t30_pinmux_init();
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+ writel(TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG);
+ writel(TEGRA_SNOR_CONFIG_GO | TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG);
+ colibri_can_resource[1].start = gpio_to_irq(TEGRA_GPIO_PS0);
+ colibri_can_resource[1].end = gpio_to_irq(TEGRA_GPIO_PS0);
+ platform_device_register(&colibri_can_device);
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
+ colibri_t30_thermd_alert_init();
+ colibri_t30_i2c_init();
+ colibri_t30_spi_init();
+ colibri_t30_usb_init();
+#ifdef CONFIG_TEGRA_EDP_LIMITS
+ colibri_t30_edp_init();
+#endif
+ colibri_t30_uart_init();
+#ifdef CONFIG_W1_MASTER_TEGRA
+ tegra_w1_device.dev.platform_data = &colibri_t30_w1_platform_data;
+#endif
+ platform_add_devices(colibri_t30_devices, ARRAY_SIZE(colibri_t30_devices));
+ tegra_ram_console_debug_init();
+ tegra_io_dpd_init();
+ colibri_t30_sdhci_init();
+ colibri_t30_regulator_init();
+ colibri_t30_suspend_init();
+ colibri_t30_panel_init();
+// colibri_t30_sensors_init();
+ colibri_t30_emc_init();
+ colibri_t30_register_spidev();
+ colibri_t20_mcp2515_can_init();
+ colibri_t30_gpio_init();
+
+#if defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE)
+ t30_get_tegra_vi01_device()->dev.platform_data = &tegra_camera_platform_data;
+#if defined(CONFIG_SOC_CAMERA_MAX9526) || defined(CONFIG_SOC_CAMERA_MAX9526_MODULE)
+ platform_device_register(&soc_camera_max9526);
+#endif
+#if defined(CONFIG_VIDEO_ADV7180) || defined(CONFIG_VIDEO_ADV7180_MODULE)
+ platform_device_register(&soc_camera_adv7180);
+#endif
+#endif /* CONFIG_VIDEO_TEGRA | CONFIG_VIDEO_TEGRA_MODULE */
+
+ tegra_release_bootloader_fb();
+#ifdef CONFIG_TEGRA_WDT_RECOVERY
+ tegra_wdt_recovery_init();
+#endif
+ tegra_serial_debug_init(TEGRA_UARTD_BASE, INT_WDT_CPU, NULL, -1, -1);
+
+ /* Activate Mic Bias */
+ gpio_request(EN_MIC_GND, "EN_MIC_GND");
+ gpio_direction_output(EN_MIC_GND, 1);
+}
+
+static void __init colibri_t30_reserve(void)
+{
+#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM)
+ /* Support 1920X1080 32bpp,double buffered on HDMI*/
+ tegra_reserve(0, SZ_8M + SZ_1M, SZ_16M);
+#else
+ tegra_reserve(SZ_128M, SZ_8M, SZ_8M);
+#endif
+ tegra_ram_console_debug_reserve(SZ_1M);
+}
+
+static const char *colibri_t30_dt_board_compat[] = {
+ "toradex,colibri_t30",
+ NULL
+};
+
+#ifdef CONFIG_ANDROID
+MACHINE_START(COLIBRI_T30, "cardhu")
+#else
+MACHINE_START(COLIBRI_T30, "Toradex Colibri T30")
+#endif
+ .boot_params = 0x80000100,
+ .dt_compat = colibri_t30_dt_board_compat,
+ .init_early = tegra_init_early,
+ .init_irq = tegra_init_irq,
+ .init_machine = colibri_t30_init,
+ .map_io = tegra_map_common_io,
+ .reserve = colibri_t30_reserve,
+ .timer = &tegra_timer,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/board-colibri_t30.h b/arch/arm/mach-tegra/board-colibri_t30.h
new file mode 100644
index 000000000000..3c67cb10f960
--- /dev/null
+++ b/arch/arm/mach-tegra/board-colibri_t30.h
@@ -0,0 +1,115 @@
+/*
+ * arch/arm/mach-tegra/board-colibri_t30.h
+ *
+ * Copyright (c) 2012 Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 _MACH_TEGRA_BOARD_COLIBRI_T30_H
+#define _MACH_TEGRA_BOARD_COLIBRI_T30_H
+
+#include <linux/mfd/tps6591x.h>
+
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+
+/* Uncomment for camera interface support on Colibri Evaluation carrier
+ board */
+#if defined(CONFIG_TEGRA_CAMERA) || defined(CONFIG_VIDEO_TEGRA) || defined(CONFIG_VIDEO_TEGRA_MODULE)
+#define COLIBRI_T30_VI
+#endif
+
+/* GPIO */
+
+#define DDC_SCL TEGRA_GPIO_PV4 /* X2-15 */
+#define DDC_SDA TEGRA_GPIO_PV5 /* X2-16 */
+
+#ifdef COLIBRI_T30_V10
+#define EMMC_DETECT TEGRA_GPIO_PC7
+#endif
+
+#define EN_MIC_GND TEGRA_GPIO_PT1
+
+#define I2C_SCL TEGRA_GPIO_PC4 /* SODIMM 196 */
+#define I2C_SDA TEGRA_GPIO_PC5 /* SODIMM 194 */
+
+#define LAN_EXT_WAKEUP TEGRA_GPIO_PDD1
+#define LAN_PME TEGRA_GPIO_PDD3
+#define LAN_RESET TEGRA_GPIO_PDD0
+#define LAN_V_BUS TEGRA_GPIO_PDD2
+
+#ifdef COLIBRI_T30_V10
+#define MMC_CD TEGRA_GPIO_PU6 /* SODIMM 43 */
+#else
+#define MMC_CD TEGRA_GPIO_PC7 /* SODIMM 43 */
+#endif
+
+#define PWR_I2C_SCL TEGRA_GPIO_PZ6
+#define PWR_I2C_SDA TEGRA_GPIO_PZ7
+
+#define THERMD_ALERT TEGRA_GPIO_PD2
+
+#define TOUCH_PEN_INT TEGRA_GPIO_PV0
+
+#define USBC_DET TEGRA_GPIO_PK5 /* SODIMM 137 */
+#define USBH_OC TEGRA_GPIO_PW3 /* SODIMM 131 */
+#define USBH_PEN TEGRA_GPIO_PW2 /* SODIMM 129 */
+
+/* Uncomment for Colibri T30 V1.0a prototypes */
+//#define COLIBRI_T30_V10
+
+/* Uncomment for SD-card on SDMMC4B rather than SDMMC2 */
+//#define COLIBRI_T30_SDMMC4B
+
+/* STMPE811 IRQs */
+#define STMPE811_IRQ_BASE TEGRA_NR_IRQS
+#define STMPE811_IRQ_END (STMPE811_IRQ_BASE + 22)
+
+#define TDIODE_OFFSET (10000) /* in millicelsius */
+#define TCRIT_LOCAL 95000 /* board temperature which switches off PMIC in millicelsius*/
+
+/* External peripheral act as gpio */
+/* TPS6591x GPIOs */
+#define TPS6591X_GPIO_BASE TEGRA_NR_GPIOS
+#define TPS6591X_GPIO_0 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP0)
+#define TPS6591X_GPIO_1 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP1)
+#define TPS6591X_GPIO_2 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP2)
+#define TPS6591X_GPIO_3 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP3)
+#define TPS6591X_GPIO_4 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP4)
+#define TPS6591X_GPIO_5 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP5)
+#define TPS6591X_GPIO_6 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP6)
+#define TPS6591X_GPIO_7 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP7)
+#define TPS6591X_GPIO_8 (TPS6591X_GPIO_BASE + TPS6591X_GPIO_GP8)
+#define TPS6591X_GPIO_END (TPS6591X_GPIO_BASE + TPS6591X_GPIO_NR)
+
+/*****************Interrupt tables ******************/
+/* External peripheral act as interrupt controller */
+/* TPS6591x IRQs */
+#define TPS6591X_IRQ_BASE STMPE811_IRQ_END
+#define TPS6591X_IRQ_END (TPS6591X_IRQ_BASE + 18)
+
+int colibri_t30_regulator_init(void);
+int colibri_t30_suspend_init(void);
+int colibri_t30_pinmux_init(void);
+int colibri_t30_panel_init(void);
+int colibri_t30_sensors_init(void);
+int colibri_t30_gpio_switch_regulator_init(void);
+int colibri_t30_pins_state_init(void);
+int colibri_t30_emc_init(void);
+int colibri_t30_power_off_init(void);
+int colibri_t30_edp_init(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/board-e1853.h b/arch/arm/mach-tegra/board-e1853.h
index 58b8ab8725af..ebd8c1b0b576 100644
--- a/arch/arm/mach-tegra/board-e1853.h
+++ b/arch/arm/mach-tegra/board-e1853.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/e1853/board-e1853.h
+ * arch/arm/mach-tegra/board-e1853.h
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
diff --git a/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c b/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c
index 718047acf896..5c5cb9b1bae0 100644
--- a/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c
+++ b/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-touch-synaptics-spi.c
+ * arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c
*
* Copyright (C) 2010-2012 NVIDIA Corporation
*
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 035a41c99359..703393ba7bd9 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/clock.h
+ * arch/arm/mach-tegra/clock.h
*
* Copyright (C) 2010 Google, Inc.
*
@@ -25,7 +25,12 @@
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
#define USE_PLL_LOCK_BITS 0 /* Never use lock bits on Tegra2 */
#else
-#define USE_PLL_LOCK_BITS 1 /* Use lock bits for PLL stabiliation */
+#if defined(CONFIG_MACH_APALIS_T30) || defined(CONFIG_MACH_COLIBRI_T30)
+/* Hack: avoid lock-up during boot-up due to missing pll_a lock bit. */
+#define USE_PLL_LOCK_BITS 0 /* Never use lock bits on Apalis/Colibri T30 */
+#else /* CONFIG_MACH_APALIS_T30 | CONFIG_MACH_COLIBRI_T30 */
+#define USE_PLL_LOCK_BITS 1 /* Use lock bits for PLL stabilisation */
+#endif /* CONFIG_MACH_APALIS_T30 | CONFIG_MACH_COLIBRI_T30 */
#define USE_PLLE_SS 1 /* Use spread spectrum coefficients for PLLE */
#define PLL_POST_LOCK_DELAY 50 /* Safety delay after lock is detected */
#endif
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 0d1407b6b668..d5acd8bdea76 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -172,6 +172,9 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
{ "pll_p_out4", "pll_p", 108000000, false },
{ "pll_m", "clk_m", 0, true },
{ "pll_m_out1", "pll_m", 120000000, true },
+//[ 0.000000] Failed to set parent pll_c_out1 for sclk (violates clock limit 240000000)
+//[ 0.000000] Unable to set parent pll_c_out1 of clock sclk: -22
+ { "pll_c_out1", "pll_c", 40000000, false },
{ "sclk", "pll_c_out1", 40000000, true },
{ "hclk", "sclk", 40000000, true },
{ "pclk", "hclk", 40000000, true },
@@ -466,6 +469,21 @@ static int __init tegra_lp0_vec_arg(char *options)
}
early_param("lp0_vec", tegra_lp0_vec_arg);
+static int __init tegra_bootloader_fb_arg0(char *options)
+{
+ char *p = options;
+
+ tegra_bootloader_fb_size = memparse(p, &p);
+ if (*p == '@')
+ tegra_bootloader_fb_start = memparse(p+1, &p);
+
+ pr_info("Found fbmem: %08lx@%08lx\n",
+ tegra_bootloader_fb_size, tegra_bootloader_fb_start);
+
+ return 0;
+}
+early_param("fbmem", tegra_bootloader_fb_arg0);
+
static int __init tegra_bootloader_fb_arg(char *options)
{
char *p = options;
@@ -496,6 +514,27 @@ static int __init tegra_bootloader_fb2_arg(char *options)
}
early_param("tegra_fbmem2", tegra_bootloader_fb2_arg);
+/* To specify NVIDIA carveout memory */
+static int __init parse_nvmem(char *p)
+{
+ unsigned long size, start;
+ char *endp;
+
+ size = memparse(p, &endp);
+ if (*endp == '@') {
+ start = memparse(endp + 1, NULL);
+ if (start && size) {
+ pr_info("Found nvmem: %08lx@%08lx\n", size, start);
+ tegra_carveout_start = start;
+ tegra_carveout_size = size;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+early_param("nvmem", parse_nvmem);
+
static int __init tegra_sku_override(char *id)
{
char *p = id;
@@ -892,6 +931,9 @@ void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
tegra_carveout_size = 0;
} else
tegra_carveout_size = carveout_size;
+ } else {
+ /* special handling due to already reserved fbmem/nvmem */
+ fb2_size -= tegra_bootloader_fb_size;
}
if (fb2_size) {
@@ -906,6 +948,11 @@ void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
tegra_fb2_size = fb2_size;
}
+ if (!carveout_size) {
+ /* special handling due to already reserved fbmem/nvmem */
+ tegra_fb2_size += tegra_bootloader_fb_size;
+ }
+
if (fb_size) {
tegra_fb_start = memblock_end_of_DRAM() - fb_size;
if (memblock_remove(tegra_fb_start, fb_size)) {
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 508320582560..c3bc1ded475a 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -886,6 +886,31 @@ struct platform_device debug_uarte_device = {
#endif
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+static struct resource tegra_ac97_resource[] = {
+ [0] = {
+ .start = INT_AC97,
+ .end = INT_AC97,
+ .flags = IORESOURCE_IRQ
+ },
+ [1] = {
+ .start = TEGRA_DMA_REQ_SEL_AC97,
+ .end = TEGRA_DMA_REQ_SEL_AC97,
+ .flags = IORESOURCE_DMA
+ },
+ [2] = {
+ .start = TEGRA_AC97_BASE,
+ .end = TEGRA_AC97_BASE + TEGRA_AC97_SIZE - 1,
+ .flags = IORESOURCE_MEM
+ }
+};
+
+struct platform_device tegra_ac97_device = {
+ .name = "tegra20-ac97",
+ .id = -1,
+ .resource = tegra_ac97_resource,
+ .num_resources = ARRAY_SIZE(tegra_ac97_resource),
+};
+
static struct resource i2s_resource1[] = {
[0] = {
.start = INT_I2S1,
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index ca492cdd11db..02962b59031f 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -75,6 +75,7 @@ extern struct platform_device tegra_udc_device;
extern struct platform_device tegra_ehci1_device;
extern struct platform_device tegra_ehci2_device;
extern struct platform_device tegra_ehci3_device;
+extern struct platform_device tegra_ac97_device;
extern struct platform_device tegra_i2s_device1;
extern struct platform_device tegra_i2s_device2;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
diff --git a/arch/arm/mach-tegra/gic.h b/arch/arm/mach-tegra/gic.h
index 22bb85f18525..bd5423ea1235 100644
--- a/arch/arm/mach-tegra/gic.h
+++ b/arch/arm/mach-tegra/gic.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/gic.h
+ * arch/arm/mach-tegra/gic.h
*
* Copyright (C) 2010-2012 NVIDIA Corporation
*
diff --git a/arch/arm/mach-tegra/gpio-names.h b/arch/arm/mach-tegra/gpio-names.h
index cb3c5ce29c0f..b1adddf12388 100644
--- a/arch/arm/mach-tegra/gpio-names.h
+++ b/arch/arm/mach-tegra/gpio-names.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/gpio-names.h
+ * arch/arm/mach-tegra/gpio-names.h
*
* Copyright (c) 2010 Google, Inc
* Copyright (C) 2011 NVIDIA Corporation.
diff --git a/arch/arm/mach-tegra/include/mach/ac97.h b/arch/arm/mach-tegra/include/mach/ac97.h
new file mode 100644
index 000000000000..a62cb93123a9
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/ac97.h
@@ -0,0 +1,87 @@
+/*
+ * arch/arm/mach-tegra/include/mach/ac97.h
+ *
+ * Copyright (C) 2011 Toradex, 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_TEGRA_AC97_H
+#define __ARCH_ARM_MACH_TEGRA_AC97_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+/* Offsets from TEGRA_AC97_BASE */
+#define AC_AC_CTRL_0 0
+#define AC_AC_CMD_0 4
+#define AC_AC_STATUS1_0 8
+/* ... */
+#define AC_AC_FIFO1_SCR_0 0x1c
+#define AC_AC_FIFO2_SCR_0 0x2c
+/* ... */
+#define AC_AC_FIFO_OUT1_0 0x40
+#define AC_AC_FIFO_IN1_0 0x80
+#define AC_AC_FIFO_OUT2_0 0x140
+#define AC_AC_FIFO_IN2_0 0x180
+
+/* AC_AC_CTRL_0 */
+#define AC_AC_CTRL_STM2_EN (1<<16)
+#define AC_AC_CTRL_DOUBLE_SAMPLING_EN (1<<11)
+#define AC_AC_CTRL_IO_CNTRL_EN (1<<10)
+#define AC_AC_CTRL_HSET_DAC_EN (1<<9)
+#define AC_AC_CTRL_LINE2_DAC_EN (1<<8)
+#define AC_AC_CTRL_PCM_LFE_EN (1<<7)
+#define AC_AC_CTRL_PCM_SUR_EN (1<<6)
+#define AC_AC_CTRL_PCM_CEN_DAC_EN (1<<5)
+#define AC_AC_CTRL_LINE1_DAC_EN (1<<4)
+#define AC_AC_CTRL_PCM_DAC_EN (1<<3)
+#define AC_AC_CTRL_COLD_RESET (1<<2)
+#define AC_AC_CTRL_WARM_RESET (1<<1)
+#define AC_AC_CTRL_STM_EN (1<<0)
+
+/* AC_AC_CMD_0 */
+#define AC_AC_CMD_CMD_ADDR_SHIFT (24)
+#define AC_AC_CMD_CMD_ADDR_MASK (0xff<<AC_AC_CMD_CMD_ADDR_SHIFT)
+#define AC_AC_CMD_CMD_DATA_SHIFT (8)
+#define AC_AC_CMD_CMD_DATA_MASK (0xffff<<AC_AC_CMD_CMD_DATA_SHIFT)
+#define AC_AC_CMD_CMD_ID_SHIFT (2)
+#define AC_AC_CMD_CMD_ID_MASK (0x3<<AC_AC_CMD_CMD_ID_SHIFT)
+#define AC_AC_CMD_BUSY (1<<0)
+
+/* AC_AC_STATUS1_0 */
+#define AC_AC_STATUS1_STA_ADDR1_SHIFT (24)
+#define AC_AC_STATUS1_STA_ADDR1_MASK (0xff<<AC_AC_STATUS1_STA_ADDR1_SHIFT)
+#define AC_AC_STATUS1_STA_DATA1_SHIFT (8)
+#define AC_AC_STATUS1_STA_DATA1_MASK (0xffff<<AC_AC_STATUS1_STA_DATA1_SHIFT)
+#define AC_AC_STATUS1_STA_VALID1 (1<<2)
+#define AC_AC_STATUS1_STANDBY1 (1<<1)
+#define AC_AC_STATUS1_CODEC1_RDY (1<<0)
+
+/* AC_AC_FIFO1_SCR_0 and AC_AC_FIFO2_SCR_0 */
+#define AC_AC_FIFOx_SCR_REC_FIFOx_MT_CNT_SHIFT (27)
+#define AC_AC_FIFOx_SCR_REC_FIFOx_MT_CNT_MASK (0x1f << REC_FIFO1_MT_CNT_SHIFT)
+#define AC_AC_FIFOx_SCR_PB_FIFOx_MT_CNT_SHIFT (22)
+#define AC_AC_FIFOx_SCR_PB_FIFOx_MT_CNT_MASK (0x1f << PB_FIFO1_MT_CNT_SHIFT)
+#define AC_AC_FIFOx_SCR_REC_FIFOx_OVERRUN_INT_STA (1<<19)
+#define AC_AC_FIFOx_SCR_PB_FIFOx_UNDERRUN_INT_STA (1<<18)
+#define AC_AC_FIFOx_SCR_RECx_FORCE_MT (1<<17)
+#define AC_AC_FIFOx_SCR_PBx_FORCE_MT (1<<16)
+#define AC_AC_FIFOx_SCR_REC_FIFOx_FULL_EN (1<<15)
+#define AC_AC_FIFOx_SCR_REC_FIFOx_3QRT_FULL_EN (1<<14)
+#define AC_AC_FIFOx_SCR_REC_FIFOx_QRT_FULL_EN (1<<13)
+#define AC_AC_FIFOx_SCR_REC_FIFOx_NOT_MT_EN (1<<12)
+#define AC_AC_FIFOx_SCR_PB_FIFOx_NOT_FULL_EN (1<<11)
+#define AC_AC_FIFOx_SCR_PB_FIFOx_QRT_MT_EN (1<<10)
+#define AC_AC_FIFOx_SCR_PB_FIFOx_3QRT_MT_EN (1<<9)
+#define AC_AC_FIFOx_SCR_PB_FIFOx_MT_EN (1<<8)
+
+#endif /* __ARCH_ARM_MACH_TEGRA_AC97_H */
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index d7aaed0bdcdc..a60e3e5b14fa 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -353,6 +353,8 @@ struct tegra_dc_out {
unsigned depth;
unsigned dither;
+ char *default_mode;
+
struct tegra_dc_mode *modes;
int n_modes;
@@ -544,10 +546,14 @@ void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val);
*/
int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n);
int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n);
+#ifndef CONFIG_ANDROID
int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable);
bool tegra_dc_is_within_n_vsync(struct tegra_dc *dc, s64 ts);
bool tegra_dc_does_vsync_separate(struct tegra_dc *dc, s64 new_ts, s64 old_ts);
+#endif /* !CONFIG_ANDROID */
+int tegra_dc_var_to_dc_mode(struct tegra_dc *dc, struct fb_var_screeninfo *var,
+ struct tegra_dc_mode *mode);
int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode);
struct fb_videomode;
int tegra_dc_set_fb_mode(struct tegra_dc *dc, const struct fb_videomode *fbmode,
@@ -592,8 +598,9 @@ struct tegra_dc_edid {
struct tegra_dc_edid *tegra_dc_get_edid(struct tegra_dc *dc);
void tegra_dc_put_edid(struct tegra_dc_edid *edid);
-int tegra_dc_set_flip_callback(void (*callback)(void));
+int tegra_dc_set_flip_callback(int (*callback)(void));
int tegra_dc_unset_flip_callback(void);
int tegra_dc_get_panel_sync_rate(void);
-
+int tegra_fb_find_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+ const char* option, unsigned int default_bpp);
#endif
diff --git a/arch/arm/mach-tegra/include/mach/kfuse.h b/arch/arm/mach-tegra/include/mach/kfuse.h
index cfe85cc86ff2..b9262a3d6d0f 100644
--- a/arch/arm/mach-tegra/include/mach/kfuse.h
+++ b/arch/arm/mach-tegra/include/mach/kfuse.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/kfuse.h
+ * arch/arm/mach-tegra/include/mach/kfuse.h
*
* Copyright (C) 2010-2011 NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h b/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
index 210b9f61ecb5..98abc9a35e3e 100644
--- a/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.c
+ * arch/arm/mach-tegra/include/mach/tegra_usb_modem_power.h
*
* Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
diff --git a/arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h b/arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h
index 944e410b4aec..50e5cc804893 100644
--- a/arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
+ * arch/arm/mach-tegra/include/mach/tegra_wm8753_pdata.h
*
* Copyright 2011 NVIDIA, Inc.
*
diff --git a/arch/arm/mach-tegra/include/mach/thermal.h b/arch/arm/mach-tegra/include/mach/thermal.h
index ed71d0340a96..12262685d7cd 100644
--- a/arch/arm/mach-tegra/include/mach/thermal.h
+++ b/arch/arm/mach-tegra/include/mach/thermal.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/thermal.h
+ * arch/arm/mach-tegra/include/mach/thermal.h
*
* Copyright (C) 2010-2012 NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-gpio.c b/arch/arm/mach-tegra/p852/board-p852-gpio.c
index 6272d36fb849..c92ca8dd2423 100644
--- a/arch/arm/mach-tegra/p852/board-p852-gpio.c
+++ b/arch/arm/mach-tegra/p852/board-p852-gpio.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-gpio.c
+ * arch/arm/mach-tegra/p852/board-p852-gpio.c
*
* Copyright (C) 2010-2011 NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-i2c.c b/arch/arm/mach-tegra/p852/board-p852-i2c.c
index 041ec252b6c1..0d197e04852f 100644
--- a/arch/arm/mach-tegra/p852/board-p852-i2c.c
+++ b/arch/arm/mach-tegra/p852/board-p852-i2c.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-i2c.c
+ * arch/arm/mach-tegra/p852/board-p852-i2c.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-panel.c b/arch/arm/mach-tegra/p852/board-p852-panel.c
index 8ed62f039dc8..579632081344 100644
--- a/arch/arm/mach-tegra/p852/board-p852-panel.c
+++ b/arch/arm/mach-tegra/p852/board-p852-panel.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-panel.c
+ * arch/arm/mach-tegra/p852/board-p852-panel.c
*
* Copyright (c) 2010-2012, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-pinmux.c b/arch/arm/mach-tegra/p852/board-p852-pinmux.c
index 0ded989f7a13..d00f23d3c32b 100644
--- a/arch/arm/mach-tegra/p852/board-p852-pinmux.c
+++ b/arch/arm/mach-tegra/p852/board-p852-pinmux.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-pinmux.c
+ * arch/arm/mach-tegra/p852/board-p852-pinmux.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sdhci.c b/arch/arm/mach-tegra/p852/board-p852-sdhci.c
index 54fd42e38ab6..f7ee9355d633 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sdhci.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sdhci.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sdhci.c
+ * arch/arm/mach-tegra/p852/board-p852-sdhci.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku1-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku1-b00.c
index 1cd89c5dfd76..7ab3671d6dd7 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku1-b00.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku1-b00.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku1-b00.c
+ * arch/arm/mach-tegra/p852/board-p852-sku1-b00.c
*
* Copyright (C) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c b/arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c
index 4a783fb9b635..ddacfa0528f9 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku1-c0x.c
+ * arch/arm/mach-tegra/p852/board-p852-sku1-c0x.c
*
* Copyright (C) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku1.c b/arch/arm/mach-tegra/p852/board-p852-sku1.c
index 387ba054bd84..09213c1955ae 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku1.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku1.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku1.c
+ * arch/arm/mach-tegra/p852/board-p852-sku1.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku13-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku13-b00.c
index 39e01f660eaf..8bf74e5e98eb 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku13-b00.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku13-b00.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku13-b00.c
+ * arch/arm/mach-tegra/p852/board-p852-sku13-b00.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku13.c b/arch/arm/mach-tegra/p852/board-p852-sku13.c
index 92d917e6e2c1..5009a43aa432 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku13.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku13.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku13.c
+ * arch/arm/mach-tegra/p852/board-p852-sku13.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku23-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku23-b00.c
index 6f464ec3620f..70f0147faffb 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku23-b00.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku23-b00.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku23-b00.c
+ * arch/arm/mach-tegra/p852/board-p852-sku23-b00.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku23-c01.c b/arch/arm/mach-tegra/p852/board-p852-sku23-c01.c
index f946e0ed35ee..b9ed72efc508 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku23-c01.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku23-c01.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku23-c01.c
+ * arch/arm/mach-tegra/p852/board-p852-sku23-c01.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku23.c b/arch/arm/mach-tegra/p852/board-p852-sku23.c
index a2bc9b4ca0b6..d61a28fea12f 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku23.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku23.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku23.c
+ * arch/arm/mach-tegra/p852/board-p852-sku23.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku3.c b/arch/arm/mach-tegra/p852/board-p852-sku3.c
index 380df9a7439a..ee6be1c53f7a 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku3.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku3.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku3.c
+ * arch/arm/mach-tegra/p852/board-p852-sku3.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku5-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku5-b00.c
index 59f6f13f7729..506fab25c968 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku5-b00.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku5-b00.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku5_b00.c
+ * arch/arm/mach-tegra/p852/board-p852-sku5-b00.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku5-c01.c b/arch/arm/mach-tegra/p852/board-p852-sku5-c01.c
index f9c8e72911b6..0dda7a21c94d 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku5-c01.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku5-c01.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku5-c01.c
+ * arch/arm/mach-tegra/p852/board-p852-sku5-c01.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku8-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku8-b00.c
index 4cc4d53d980f..e9a11b427de1 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku8-b00.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku8-b00.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku8-b00.c
+ * arch/arm/mach-tegra/p852/board-p852-sku8-b00.c
*
* Copyright (C) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku8-c01.c b/arch/arm/mach-tegra/p852/board-p852-sku8-c01.c
index 71210cd12b90..f1da518f2eef 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku8-c01.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku8-c01.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku8-c00.c
+ * arch/arm/mach-tegra/p852/board-p852-sku8-c01.c
*
* Copyright (C) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku9-b00.c b/arch/arm/mach-tegra/p852/board-p852-sku9-b00.c
index 7c3d9c3d9a3d..fd2f1cb95716 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku9-b00.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku9-b00.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku9-b00.c
+ * arch/arm/mach-tegra/p852/board-p852-sku9-b00.c
*
* Copyright (C) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852-sku9-c01.c b/arch/arm/mach-tegra/p852/board-p852-sku9-c01.c
index 94c79294fb47..9add0e83a0d3 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sku9-c01.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sku9-c01.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852-sku9-c00.c
+ * arch/arm/mach-tegra/p852/board-p852-sku9-c01.c
*
* Copyright (C) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852.c b/arch/arm/mach-tegra/p852/board-p852.c
index 0382d7306f42..fba0db4a1a05 100644
--- a/arch/arm/mach-tegra/p852/board-p852.c
+++ b/arch/arm/mach-tegra/p852/board-p852.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852.c
+ * arch/arm/mach-tegra/p852/board-p852.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/p852/board-p852.h b/arch/arm/mach-tegra/p852/board-p852.h
index 8e8f1444029c..58934e6dc1cc 100644
--- a/arch/arm/mach-tegra/p852/board-p852.h
+++ b/arch/arm/mach-tegra/p852/board-p852.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/board-p852.h
+ * arch/arm/mach-tegra/p852/board-p852.h
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index 04d3a5db3f7e..efeb2c48277e 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -289,7 +289,7 @@
struct tegra_pcie_port {
int index;
- u8 root_bus_nr;
+ int root_bus_nr;
void __iomem *base;
bool link_up;
@@ -1262,6 +1262,7 @@ static void tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
tegra_pcie.num_ports++;
pp->index = index;
+ pp->root_bus_nr = -1;
memset(pp->res, 0, sizeof(pp->res));
}
diff --git a/arch/arm/mach-tegra/pm-t3.c b/arch/arm/mach-tegra/pm-t3.c
index 939a9b8ad404..dbc10f229551 100644
--- a/arch/arm/mach-tegra/pm-t3.c
+++ b/arch/arm/mach-tegra/pm-t3.c
@@ -478,9 +478,15 @@ void tegra_lp0_cpu_mode(bool enter)
struct tegra_io_dpd tegra_list_io_dpd[] = {
/* sd dpd bits in dpd2 register */
+#ifndef CONFIG_MACH_APALIS_T30
+/* Hack: fix MMC1 card detection */
IO_DPD_INFO("sdhci-tegra.0", 1, 1), /* SDMMC1 */
+#endif
IO_DPD_INFO("sdhci-tegra.2", 1, 2), /* SDMMC3 */
+#if !defined(CONFIG_MACH_APALIS_T30) && !defined(CONFIG_MACH_COLIBRI_T30)
+/* Hack: fix eMMC detection */
IO_DPD_INFO("sdhci-tegra.3", 1, 3), /* SDMMC4 */
+#endif
};
/* we want to cleanup bootloader io dpd setting in kernel */
diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h
index 401c0aaf061f..284c556d2a93 100644
--- a/arch/arm/mach-tegra/pm.h
+++ b/arch/arm/mach-tegra/pm.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/pm.h
+ * arch/arm/mach-tegra/pm.h
*
* Copyright (C) 2010 Google, Inc.
* Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved.
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 4c0d8bec276e..c6d215fc025c 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -721,6 +721,7 @@ err_power:
WARN(1, "Could not Un-Powergate %d", id);
return ret;
}
+EXPORT_SYMBOL(tegra_unpowergate_partition);
/*
* Must be called with clk disabled, and returns with clk enabled
diff --git a/arch/arm/mach-tegra/sleep-t2.S b/arch/arm/mach-tegra/sleep-t2.S
index f70360628f34..0b77fd14c7c2 100644
--- a/arch/arm/mach-tegra/sleep-t2.S
+++ b/arch/arm/mach-tegra/sleep-t2.S
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/sleep-t2.S
+ * arch/arm/mach-tegra/sleep-t2.S
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
* Copyright (c) 2011, Google, Inc.
diff --git a/arch/arm/mach-tegra/sleep-t3.S b/arch/arm/mach-tegra/sleep-t3.S
index 4ee73d581a08..ae943bde1ce2 100644
--- a/arch/arm/mach-tegra/sleep-t3.S
+++ b/arch/arm/mach-tegra/sleep-t3.S
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/sleep-t3.S
+ * arch/arm/mach-tegra/sleep-t3.S
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 08359fcc0d31..58d2dcddbfaa 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -65,8 +65,9 @@
#define PERIPH_CLK_SOURCE_NUM \
((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
-#define PERIPH_CLK_SOURCE_MASK (3<<30)
-#define PERIPH_CLK_SOURCE_SHIFT 30
+//special handling for pwm clock source, uses 3 bits 30:28 instead of 2 bits 31:30
+#define PERIPH_CLK_SOURCE_MASK ((c->reg) != 0x110 ? (3<<PERIPH_CLK_SOURCE_SHIFT) : (7<<PERIPH_CLK_SOURCE_SHIFT))
+#define PERIPH_CLK_SOURCE_SHIFT ((c->reg) != 0x110 ? 30 : 28)
#define PERIPH_CLK_SOURCE_ENABLE (1<<28)
#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
@@ -2103,9 +2104,9 @@ static const struct audio_sources {
{ .name = "spdif_in", .value = 0 },
{ .name = "i2s1", .value = 1 },
{ .name = "i2s2", .value = 2 },
+ { .name = "ac97", .value = 3 },
{ .name = "pll_a_out0", .value = 4 },
#if 0 /* FIXME: not implemented */
- { .name = "ac97", .value = 3 },
{ .name = "ext_audio_clk2", .value = 5 },
{ .name = "ext_audio_clk1", .value = 6 },
{ .name = "ext_vimclk", .value = 7 },
@@ -2428,6 +2429,7 @@ struct clk tegra_list_periph_clks[] = {
PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 0x31E, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
PERIPH_CLK("kbc", "tegra-kbc", NULL, 36, 0, 0x31E, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
PERIPH_CLK("timer", "timer", NULL, 5, 0, 0x31E, 26000000, mux_clk_m, 0),
+ PERIPH_CLK("ac97", "tegra20-ac97", NULL, 3, 0, 0x31E, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("i2s1", "tegra20-i2s.0", NULL, 11, 0x100, 0x31E, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("i2s2", "tegra20-i2s.1", NULL, 18, 0x104, 0x31E, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("fuse", "fuse-tegra", "fuse", 39, 0, 0x31E, 26000000, mux_clk_m, PERIPH_ON_APB),
@@ -2755,7 +2757,7 @@ struct tegra_cpufreq_table_data *tegra_cpufreq_table_get(void)
unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate)
{
/* Vote on memory bus frequency based on cpu frequency */
- if (cpu_rate > 1000000000)
+ if (cpu_rate > 1000000)
return 760000000;
else if (cpu_rate >= 816000)
return 600000000; /* cpu 816 MHz, emc max */
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c
index f1ac82ad5c15..4986fffcfed7 100644
--- a/arch/arm/mach-tegra/tegra2_emc.c
+++ b/arch/arm/mach-tegra/tegra2_emc.c
@@ -54,6 +54,7 @@ static inline u32 emc_readl(unsigned long addr)
return readl(emc + addr);
}
+#ifndef CONFIG_MACH_COLIBRI_T20
/* read LPDDR2 memory modes */
static int tegra_emc_read_mrr(unsigned long addr)
{
@@ -82,6 +83,7 @@ static int tegra_emc_read_mrr(unsigned long addr)
return value;
}
+#endif /* !CONFIG_MACH_COLIBRI_T20 */
static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
0x2c, /* RC */
@@ -219,18 +221,25 @@ int tegra_emc_set_rate(unsigned long rate)
void tegra_init_emc(const struct tegra_emc_chip *chips, int chips_size)
{
int i;
+#ifndef CONFIG_MACH_COLIBRI_T20
int vid;
int rev_id1;
int rev_id2;
int pid;
+#endif /* !CONFIG_MACH_COLIBRI_T20 */
int chip_matched = -1;
+#ifndef CONFIG_MACH_COLIBRI_T20
+//somehow this only seems to work for LPDDR2 but we have regular DDR2
vid = tegra_emc_read_mrr(5);
rev_id1 = tegra_emc_read_mrr(6);
rev_id2 = tegra_emc_read_mrr(7);
pid = tegra_emc_read_mrr(8);
+#endif /* !CONFIG_MACH_COLIBRI_T20 */
for (i = 0; i < chips_size; i++) {
+#ifndef CONFIG_MACH_COLIBRI_T20
+//for now just go with the one and only chip table
if (chips[i].mem_manufacturer_id >= 0) {
if (chips[i].mem_manufacturer_id != vid)
continue;
@@ -247,6 +256,7 @@ void tegra_init_emc(const struct tegra_emc_chip *chips, int chips_size)
if (chips[i].mem_pid != pid)
continue;
}
+#endif /* !CONFIG_MACH_COLIBRI_T20 */
chip_matched = i;
break;
@@ -264,9 +274,11 @@ void tegra_init_emc(const struct tegra_emc_chip *chips, int chips_size)
} else {
pr_err("%s: Memory not recognized, memory scaling disabled\n",
__func__);
+#ifndef CONFIG_MACH_COLIBRI_T20
pr_info("%s: Memory vid = 0x%04x", __func__, vid);
pr_info("%s: Memory rev_id1 = 0x%04x", __func__, rev_id1);
pr_info("%s: Memory rev_id2 = 0x%04x", __func__, rev_id2);
pr_info("%s: Memory pid = 0x%04x", __func__, pid);
+#endif /* !CONFIG_MACH_COLIBRI_T20 */
}
}
diff --git a/arch/arm/mach-tegra/tegra2_mc.h b/arch/arm/mach-tegra/tegra2_mc.h
index 211213c5f585..9ff27cbca3f1 100644
--- a/arch/arm/mach-tegra/tegra2_mc.h
+++ b/arch/arm/mach-tegra/tegra2_mc.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/tegra2_mc.c
+ * arch/arm/mach-tegra/tegra2_mc.h
*
* Memory controller bandwidth profiling interface
*
diff --git a/arch/arm/mach-tegra/tegra2_usb_phy.c b/arch/arm/mach-tegra/tegra2_usb_phy.c
index 0292ebb75083..121a84b2bcb0 100644
--- a/arch/arm/mach-tegra/tegra2_usb_phy.c
+++ b/arch/arm/mach-tegra/tegra2_usb_phy.c
@@ -629,6 +629,8 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy)
} else if (!phy->phy_clk_on) {
return IRQ_NONE;
}
+ } else if (!phy->phy_clk_on) {
+ return IRQ_NONE;
}
return IRQ_HANDLED;
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index 0bc60869a3d0..fafa5a22157a 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -844,12 +844,15 @@ static int tegra3_cpu_clk_set_rate(struct clk *c, unsigned long rate)
if (c->dvfs) {
if (!c->dvfs->dvfs_rail)
return -ENOSYS;
+#if !defined(CONFIG_MACH_APALIS_T30) && !defined(CONFIG_MACH_COLIBRI_T30)
+/* Hack: avoid extensive warnings being logged during boot-up. */
else if ((!c->dvfs->dvfs_rail->reg) &&
(clk_get_rate_locked(c) < rate)) {
WARN(1, "Increasing CPU rate while regulator is not"
" ready may overclock CPU\n");
return -ENOSYS;
}
+#endif /* !CONFIG_MACH_APALIS_T30 & !CONFIG_MACH_COLIBRI_T30 */
}
/*
diff --git a/arch/arm/mach-tegra/tegra3_speedo.c b/arch/arm/mach-tegra/tegra3_speedo.c
index b91135c5634d..76303b4f1756 100644
--- a/arch/arm/mach-tegra/tegra3_speedo.c
+++ b/arch/arm/mach-tegra/tegra3_speedo.c
@@ -198,7 +198,7 @@ static void rev_sku_to_speedo_ids(int rev, int sku)
break;
case 0x81: /* T30 */
- case 0xb1:
+ case 0xb1: /* T30MQS-Ax */
switch (package_id) {
case 1: /* MID => T30 */
cpu_speedo_id = 2;
diff --git a/arch/arm/mach-tegra/tegra_fiq_debugger.c b/arch/arm/mach-tegra/tegra_fiq_debugger.c
index 2a19a214acb5..d164d6b1d949 100644
--- a/arch/arm/mach-tegra/tegra_fiq_debugger.c
+++ b/arch/arm/mach-tegra/tegra_fiq_debugger.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/fiq_debugger.c
+ * arch/arm/mach-tegra/tegra_fiq_debugger.c
*
* Serial Debugger Interface for Tegra
*
diff --git a/arch/arm/mach-tegra/tegra_usb_phy.h b/arch/arm/mach-tegra/tegra_usb_phy.h
index 05aa88296619..ff3b979fe814 100644
--- a/arch/arm/mach-tegra/tegra_usb_phy.h
+++ b/arch/arm/mach-tegra/tegra_usb_phy.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/tegra_usb_phy.h
+ * arch/arm/mach-tegra/tegra_usb_phy.h
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index 2a7364c12753..b5d3dc575e0c 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -79,6 +79,7 @@ static void print_usb_plat_data_info(struct tegra_usb_phy *phy)
? "enabled" : "disabled");
} else {
pr_info("vbus_gpio: %d\n", pdata->u_data.host.vbus_gpio);
+ pr_info("vbus_gpio_inverted: %d\n", pdata->u_data.host.vbus_gpio_inverted);
pr_info("vbus_reg: %s\n", pdata->u_data.host.vbus_reg ?
pdata->u_data.host.vbus_reg : "NULL");
pr_info("hot_plug: %s\n", pdata->u_data.host.hot_plug ?
@@ -99,7 +100,7 @@ static void usb_host_vbus_enable(struct tegra_usb_phy *phy, bool enable)
int gpio = phy->pdata->u_data.host.vbus_gpio;
if (gpio == -1)
return;
- gpio_set_value_cansleep(gpio, enable ? 1 : 0);
+ gpio_set_value_cansleep(gpio, (enable != phy->pdata->u_data.host.vbus_gpio_inverted)? 1 : 0);
}
}
@@ -326,7 +327,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev)
req failed\n", phy->inst);
goto fail_init;
}
- if (gpio_direction_output(gpio, 1) < 0) {
+ if (gpio_direction_output(gpio, !phy->pdata->u_data.host.vbus_gpio_inverted) < 0) {
ERR("inst:[%d] host vbus gpio \
dir failed\n", phy->inst);
goto fail_init;
@@ -369,7 +370,7 @@ fail_init:
else {
int gpio = phy->pdata->u_data.host.vbus_gpio;
if (gpio != -1) {
- gpio_set_value_cansleep(gpio, 0);
+ gpio_set_value_cansleep(gpio, phy->pdata->u_data.host.vbus_gpio_inverted);
gpio_free(gpio);
}
}
@@ -386,6 +387,7 @@ fail_nomem:
fail_inval:
return ERR_PTR(err);
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
void tegra_usb_phy_close(struct tegra_usb_phy *phy)
{
@@ -410,7 +412,7 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy)
else {
int gpio = phy->pdata->u_data.host.vbus_gpio;
if (gpio != -1) {
- gpio_set_value_cansleep(gpio, 0);
+ gpio_set_value_cansleep(gpio, phy->pdata->u_data.host.vbus_gpio_inverted);
gpio_free(gpio);
}
}
@@ -427,6 +429,7 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy)
devm_kfree(&phy->pdev->dev, phy->pdata);
devm_kfree(&phy->pdev->dev, phy);
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_close);
irqreturn_t tegra_usb_phy_irq(struct tegra_usb_phy *phy)
{
@@ -452,6 +455,7 @@ int tegra_usb_phy_init(struct tegra_usb_phy *phy)
return status;
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_init);
int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
{
@@ -502,6 +506,7 @@ int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
return err;
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_power_off);
int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
{
@@ -546,6 +551,7 @@ int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
return status;
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_power_on);
int tegra_usb_phy_reset(struct tegra_usb_phy *phy)
{
@@ -685,6 +691,7 @@ bool tegra_usb_phy_charger_detected(struct tegra_usb_phy *phy)
return status;
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_charger_detected);
bool tegra_usb_phy_hw_accessible(struct tegra_usb_phy *phy)
{
@@ -704,11 +711,13 @@ bool tegra_usb_phy_has_hostpc(struct tegra_usb_phy *phy)
{
return phy->pdata->has_hostpc;
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_has_hostpc);
bool tegra_usb_phy_otg_supported(struct tegra_usb_phy *phy)
{
return phy->pdata->port_otg;
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_otg_supported);
void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy)
{
@@ -724,6 +733,7 @@ void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy)
writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG2);
}
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_memory_prefetch_on);
void tegra_usb_phy_memory_prefetch_off(struct tegra_usb_phy *phy)
{
@@ -739,3 +749,4 @@ void tegra_usb_phy_memory_prefetch_off(struct tegra_usb_phy *phy)
writel(val, ahb_gizmo + AHB_MEM_PREFETCH_CFG2);
}
}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_memory_prefetch_off);
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 3b5ea68acbb8..aa33949fef60 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -20,6 +20,7 @@
#include <linux/highmem.h>
#include <linux/perf_event.h>
+#include <asm/exception.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c
index c11064517f56..f5519a93147d 100644
--- a/arch/arm/mm/pageattr.c
+++ b/arch/arm/mm/pageattr.c
@@ -35,7 +35,9 @@ extern void __flush_dcache_page(struct address_space *, struct page *);
static void inner_flush_cache_all(void)
{
+#ifdef CONFIG_CPU_CACHE_V7
on_each_cpu(v7_flush_kern_cache_all, NULL, 1);
+#endif
}
#if defined(CONFIG_CPA)
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 978683edfead..3f55d34e3f39 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -946,7 +946,7 @@ shenzhou MACH_SHENZHOU SHENZHOU 3319
cwme9210 MACH_CWME9210 CWME9210 3320
cwme9210js MACH_CWME9210JS CWME9210JS 3321
pgs_v1 MACH_PGS_SITARA PGS_SITARA 3322
-colibri_tegra2 MACH_COLIBRI_TEGRA2 COLIBRI_TEGRA2 3323
+colibri_t20 MACH_COLIBRI_T20 COLIBRI_T20 3323
w21 MACH_W21 W21 3324
polysat1 MACH_POLYSAT1 POLYSAT1 3325
dataway MACH_DATAWAY DATAWAY 3326
@@ -1119,3 +1119,5 @@ kai MACH_KAI KAI 3897
p852 MACH_P852 P852 3667
e1853 MACH_E1853 E1853 4241
tai MACH_TAI TAI 4311
+colibri_t30 MACH_COLIBRI_T30 COLIBRI_T30 4493
+apalis_t30 MACH_APALIS_T30 APALIS_T30 4513
diff --git a/drivers/ata/ahci-tegra.c b/drivers/ata/ahci-tegra.c
index c90472827b9b..32bf46940b0f 100644
--- a/drivers/ata/ahci-tegra.c
+++ b/drivers/ata/ahci-tegra.c
@@ -217,6 +217,7 @@ enum sata_state {
};
char *sata_power_rails[] = {
+ "avdd_plle",
"avdd_sata",
"vdd_sata",
"hvdd_sata",
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
index dce9e68241e6..1b60fe6de776 100644
--- a/drivers/hwmon/lm95245.c
+++ b/drivers/hwmon/lm95245.c
@@ -34,6 +34,8 @@
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/lm95245.h>
+
#define DEVNAME "lm95245"
static const unsigned short normal_i2c[] = {
@@ -93,6 +95,7 @@ static const unsigned short normal_i2c[] = {
#define RATE_CR1000 0x02
#define RATE_CR2500 0x03
+#define STATUS1_ROS 0x10
#define STATUS1_DIODE_FAULT 0x04
#define STATUS1_RTCRIT 0x02
#define STATUS1_LOC 0x01
@@ -107,12 +110,32 @@ static const u8 lm95245_reg_address[] = {
LM95245_REG_R_REMOTE_TEMPL_S,
LM95245_REG_R_REMOTE_TEMPH_U,
LM95245_REG_R_REMOTE_TEMPL_U,
+ LM95245_REG_RW_REMOTE_OS_LIMIT,
LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT,
LM95245_REG_RW_REMOTE_TCRIT_LIMIT,
LM95245_REG_RW_COMMON_HYSTERESIS,
LM95245_REG_R_STATUS1,
};
+/* Indices and offsets into above register array */
+
+enum {
+ INDEX_LOCAL_TEMP = 0,
+ INDEX_REMOTE_TEMP = 2,
+ INDEX_REMOTE_OS_LIMIT = 6,
+ INDEX_LOCAL_OS_TCRIT_LIMIT,
+ INDEX_REMOTE_TCRIT_LIMIT,
+ INDEX_COMMON_HYSTERESIS,
+ INDEX_STATUS1,
+};
+
+enum {
+ OFFSET_HIGH_SIGNED = 0,
+ OFFSET_LOW_SIGNED,
+ OFFSET_HIGH_UNSIGNED,
+ OFFSET_LOW_UNSIGNED,
+};
+
/* Client data (each client gets its own) */
struct lm95245_data {
struct device *hwmon_dev;
@@ -214,24 +237,42 @@ static unsigned long lm95245_set_conversion_rate(struct i2c_client *client,
}
/* Sysfs stuff */
-static ssize_t show_input(struct device *dev, struct device_attribute *attr,
- char *buf)
+void thermal_get_temp(struct device *dev, int *temp, int index)
{
struct lm95245_data *data = lm95245_update_device(dev);
- int temp;
- int index = to_sensor_dev_attr(attr)->index;
/*
- * Index 0 (Local temp) is always signed
- * Index 2 (Remote temp) has both signed and unsigned data
+ * Local temp is always signed
+ * Remote temp has both signed and unsigned data
* use signed calculation for remote if signed bit is set
*/
- if (index == 0 || data->regs[index] & 0x80)
- temp = temp_from_reg_signed(data->regs[index],
- data->regs[index + 1]);
+ if (index == INDEX_LOCAL_TEMP || data->regs[index + OFFSET_HIGH_SIGNED] & 0x80)
+ *temp = temp_from_reg_signed(data->regs[index + OFFSET_HIGH_SIGNED],
+ data->regs[index + OFFSET_LOW_SIGNED]);
else
- temp = temp_from_reg_unsigned(data->regs[index + 2],
- data->regs[index + 3]);
+ *temp = temp_from_reg_unsigned(data->regs[index + OFFSET_HIGH_UNSIGNED],
+ data->regs[index + OFFSET_LOW_UNSIGNED]);
+}
+
+void lm95245_get_local_temp(struct device *dev, int *temp)
+{
+ thermal_get_temp(dev, temp, INDEX_LOCAL_TEMP);
+}
+EXPORT_SYMBOL(lm95245_get_local_temp);
+
+void lm95245_get_remote_temp(struct device *dev, int *temp)
+{
+ thermal_get_temp(dev, temp, INDEX_REMOTE_TEMP);
+}
+EXPORT_SYMBOL(lm95245_get_remote_temp);
+
+static ssize_t show_input(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int temp = 0;
+ int index = to_sensor_dev_attr(attr)->index;
+
+ thermal_get_temp(dev, &temp, index);
return snprintf(buf, PAGE_SIZE - 1, "%d\n", temp);
}
@@ -246,20 +287,14 @@ static ssize_t show_limit(struct device *dev, struct device_attribute *attr,
data->regs[index] * 1000);
}
-static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+void thermal_set_limit(struct device *dev, int val, int index)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm95245_data *data = i2c_get_clientdata(client);
- int index = to_sensor_dev_attr(attr)->index;
- unsigned long val;
-
- if (strict_strtoul(buf, 10, &val) < 0)
- return -EINVAL;
val /= 1000;
- val = SENSORS_LIMIT(val, 0, (index == 6 ? 127 : 255));
+ val = SENSORS_LIMIT(val, 0, (index == INDEX_LOCAL_OS_TCRIT_LIMIT ? 127 : 255));
mutex_lock(&data->update_lock);
@@ -268,6 +303,36 @@ static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
i2c_smbus_write_byte_data(client, lm95245_reg_address[index], val);
mutex_unlock(&data->update_lock);
+}
+
+void lm95245_set_remote_os_limit(struct device *dev, int val)
+{
+ thermal_set_limit(dev, val, INDEX_REMOTE_OS_LIMIT);
+}
+EXPORT_SYMBOL(lm95245_set_remote_os_limit);
+
+void lm95245_set_remote_critical_limit(struct device *dev, int val)
+{
+ thermal_set_limit(dev, val, INDEX_REMOTE_TCRIT_LIMIT);
+}
+EXPORT_SYMBOL(lm95245_set_remote_critical_limit);
+
+void lm95245_set_local_shared_os__critical_limit(struct device *dev, int val)
+{
+ thermal_set_limit(dev, val, INDEX_LOCAL_OS_TCRIT_LIMIT);
+}
+EXPORT_SYMBOL(lm95245_set_local_shared_os__critical_limit);
+
+static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val) < 0)
+ return -EINVAL;
+
+ thermal_set_limit(dev, (int)val, index);
return count;
}
@@ -345,7 +410,7 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
int index = to_sensor_dev_attr(attr)->index;
return snprintf(buf, PAGE_SIZE - 1, "%d\n",
- !!(data->regs[9] & index));
+ !!(data->regs[INDEX_STATUS1] & index));
}
static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
@@ -375,19 +440,23 @@ static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
return count;
}
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, INDEX_LOCAL_TEMP);
static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit,
- set_limit, 6);
+ set_limit, INDEX_LOCAL_OS_TCRIT_LIMIT);
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
- set_crit_hyst, 8);
+ set_crit_hyst, INDEX_COMMON_HYSTERESIS);
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
STATUS1_LOC);
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, INDEX_REMOTE_TEMP);
+static SENSOR_DEVICE_ATTR(temp2_os, S_IWUSR | S_IRUGO, show_limit,
+ set_limit, INDEX_REMOTE_OS_LIMIT);
static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit,
- set_limit, 7);
+ set_limit, INDEX_REMOTE_TCRIT_LIMIT);
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
- set_crit_hyst, 8);
+ set_crit_hyst, INDEX_COMMON_HYSTERESIS);
+static SENSOR_DEVICE_ATTR(temp2_os_alarm, S_IRUGO, show_alarm, NULL,
+ STATUS1_ROS);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
STATUS1_RTCRIT);
static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type,
@@ -404,8 +473,10 @@ static struct attribute *lm95245_attributes[] = {
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_os.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_os_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_type.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
@@ -454,6 +525,13 @@ static void lm95245_init_client(struct i2c_client *client)
i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG1,
data->config1);
}
+
+ /* Configure over-temperature shutdown (OS) output pin */
+ if (client->dev.platform_data && ((struct lm95245_platform_data*)(client->dev.platform_data))->enable_os_pin) {
+ data->config2 |= CFG2_OS_A0;
+ i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG2,
+ data->config2);
+ }
}
static int lm95245_probe(struct i2c_client *new_client,
@@ -485,6 +563,10 @@ static int lm95245_probe(struct i2c_client *new_client,
goto exit_remove_files;
}
+ /* Notify callback that probe is done */
+ if (new_client->dev.platform_data && ((struct lm95245_platform_data*)(new_client->dev.platform_data))->probe_callback)
+ ((struct lm95245_platform_data*)(new_client->dev.platform_data))->probe_callback(&new_client->dev);
+
return 0;
exit_remove_files:
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 1def6f105d6b..ec1bd9009288 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -790,7 +790,7 @@ static int gpio_keys_suspend(struct device *dev)
for (i = 0; i < ddata->n_buttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
if (bdata->button->wakeup)
- enable_irq_wake(bdata->irq);
+ WARN_ON(enable_irq_wake(bdata->irq));
}
}
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index a8fc74f730dd..936f1e71a21f 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -770,4 +770,11 @@ config TOUCHSCREEN_SYN_RMI4_SPI
To compile this driver as a module, choose M here: the
module will be called rmi-spi.
+config TOUCHSCREEN_FUSION_F0710A
+ tristate "TouchRevolution Fusion F0710A Touchscreens"
+ depends on I2C
+ help
+ Say Y here if you want to support the multi-touch input driver for
+ the TouchRevolution Fusion 7 and 10 panels.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 9c42d2100b5c..2fa571b65088 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -64,3 +64,4 @@ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_RM31080A) += rm31080a_ts.o
obj-$(CONFIG_TOUCHSCREEN_SYN_RMI4_SPI) += rmi4/
+obj-$(CONFIG_TOUCHSCREEN_FUSION_F0710A) += fusion_F0710A.o
diff --git a/drivers/input/touchscreen/fusion_F0710A.c b/drivers/input/touchscreen/fusion_F0710A.c
new file mode 100644
index 000000000000..c5c0f1fc38ea
--- /dev/null
+++ b/drivers/input/touchscreen/fusion_F0710A.c
@@ -0,0 +1,524 @@
+/*
+ * "fusion_F0710A" touchscreen driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <linux/gpio.h>
+#include <linux/input/fusion_F0710A.h>
+
+#include "fusion_F0710A.h"
+
+#define DRV_NAME "fusion_F0710A"
+
+
+static struct fusion_F0710A_data fusion_F0710A;
+
+static unsigned short normal_i2c[] = { fusion_F0710A_I2C_SLAVE_ADDR, I2C_CLIENT_END };
+
+//I2C_CLIENT_INSMOD;
+
+static int fusion_F0710A_write_u8(u8 addr, u8 data)
+{
+ return i2c_smbus_write_byte_data(fusion_F0710A.client, addr, data);
+}
+
+static int fusion_F0710A_read_u8(u8 addr)
+{
+ return i2c_smbus_read_byte_data(fusion_F0710A.client, addr);
+}
+
+static int fusion_F0710A_read_block(u8 addr, u8 len, u8 *data)
+{
+#if 0
+ /* When i2c_smbus_read_i2c_block_data() takes a block length parameter, we can do
+ * this. lm-sensors lists hints this has been fixed, but I can't tell whether it
+ * was or will be merged upstream. */
+
+ return i2c_smbus_read_i2c_block_data(&fusion_F0710A.client, addr, data);
+#else
+ u8 msgbuf0[1] = { addr };
+ u16 slave = fusion_F0710A.client->addr;
+ u16 flags = fusion_F0710A.client->flags;
+ struct i2c_msg msg[2] = { { slave, flags, 1, msgbuf0 },
+ { slave, flags | I2C_M_RD, len, data }
+ };
+
+ return i2c_transfer(fusion_F0710A.client->adapter, msg, ARRAY_SIZE(msg));
+#endif
+}
+
+
+static int fusion_F0710A_register_input(void)
+{
+ int ret;
+ struct input_dev *dev;
+
+ dev = fusion_F0710A.input = input_allocate_device();
+ if (dev == NULL)
+ return -ENOMEM;
+
+ dev->name = "fusion_F0710A";
+
+ set_bit(EV_KEY, dev->evbit);
+ set_bit(EV_ABS, dev->evbit);
+
+ input_set_abs_params(dev, ABS_MT_POSITION_X, 0, fusion_F0710A.info.xres-1, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, fusion_F0710A.info.yres-1, 0, 0);
+#ifdef CONFIG_ANDROID
+ input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
+#else
+ input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(dev, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0);
+#endif
+
+ input_set_abs_params(dev, ABS_X, 0, fusion_F0710A.info.xres-1, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, fusion_F0710A.info.yres-1, 0, 0);
+ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
+
+ ret = input_register_device(dev);
+ if (ret < 0)
+ goto bail1;
+
+ return 0;
+
+bail1:
+ input_free_device(dev);
+ return ret;
+}
+
+#define WC_RETRY_COUNT 3
+static int fusion_F0710A_write_complete(void)
+{
+ int ret, i;
+
+ for(i=0; i<WC_RETRY_COUNT; i++)
+ {
+ ret = fusion_F0710A_write_u8(fusion_F0710A_SCAN_COMPLETE, 0);
+ if(ret == 0)
+ break;
+ else
+ dev_err(&fusion_F0710A.client->dev, "Write complete failed(%d): %d\n", i, ret);
+ }
+
+ return ret;
+}
+
+#define DATA_START fusion_F0710A_DATA_INFO
+#define DATA_END fusion_F0710A_SEC_TIDTS
+#define DATA_LEN (DATA_END - DATA_START + 1)
+#define DATA_OFF(x) ((x) - DATA_START)
+
+static int fusion_F0710A_read_sensor(void)
+{
+ int ret;
+ u8 data[DATA_LEN];
+
+#define DATA(x) (data[DATA_OFF(x)])
+ /* To ensure data coherency, read the sensor with a single transaction. */
+ ret = fusion_F0710A_read_block(DATA_START, DATA_LEN, data);
+ if (ret < 0) {
+ dev_err(&fusion_F0710A.client->dev,
+ "Read block failed: %d\n", ret);
+
+ return ret;
+ }
+
+ fusion_F0710A.f_num = DATA(fusion_F0710A_DATA_INFO)&0x03;
+
+ fusion_F0710A.y1 = DATA(fusion_F0710A_POS_X1_HI) << 8;
+ fusion_F0710A.y1 |= DATA(fusion_F0710A_POS_X1_LO);
+ fusion_F0710A.x1 = DATA(fusion_F0710A_POS_Y1_HI) << 8;
+ fusion_F0710A.x1 |= DATA(fusion_F0710A_POS_Y1_LO);
+ fusion_F0710A.z1 = DATA(fusion_F0710A_FIR_PRESS);
+ fusion_F0710A.tip1 = DATA(fusion_F0710A_FIR_TIDTS)&0x0f;
+ fusion_F0710A.tid1 = (DATA(fusion_F0710A_FIR_TIDTS)&0xf0)>>4;
+
+
+ fusion_F0710A.y2 = DATA(fusion_F0710A_POS_X2_HI) << 8;
+ fusion_F0710A.y2 |= DATA(fusion_F0710A_POS_X2_LO);
+ fusion_F0710A.x2 = DATA(fusion_F0710A_POS_Y2_HI) << 8;
+ fusion_F0710A.x2 |= DATA(fusion_F0710A_POS_Y2_LO);
+ fusion_F0710A.z2 = DATA(fusion_F0710A_SEC_PRESS);
+ fusion_F0710A.tip2 = DATA(fusion_F0710A_SEC_TIDTS)&0x0f;
+ fusion_F0710A.tid2 =(DATA(fusion_F0710A_SEC_TIDTS)&0xf0)>>4;
+#undef DATA
+
+ return 0;
+}
+
+#define val_cut_max(x, max, reverse) \
+do \
+{ \
+ if(x > max) \
+ x = max; \
+ if(reverse) \
+ x = (max) - (x); \
+} \
+while(0)
+
+static void fusion_F0710A_wq(struct work_struct *work)
+{
+ struct input_dev *dev = fusion_F0710A.input;
+ int save_points = 0;
+ int x1 = 0, y1 = 0, z1 = 0, x2 = 0, y2 = 0, z2 = 0;
+
+ if (fusion_F0710A_read_sensor() < 0)
+ goto restore_irq;
+
+#ifdef DEBUG
+ printk(KERN_DEBUG "tip1, tid1, x1, y1, z1 (%x,%x,%d,%d,%d); tip2, tid2, x2, y2, z2 (%x,%x,%d,%d,%d)\n",
+ fusion_F0710A.tip1, fusion_F0710A.tid1, fusion_F0710A.x1, fusion_F0710A.y1, fusion_F0710A.z1,
+ fusion_F0710A.tip2, fusion_F0710A.tid2, fusion_F0710A.x2, fusion_F0710A.y2, fusion_F0710A.z2);
+#endif /* DEBUG */
+
+ val_cut_max(fusion_F0710A.x1, fusion_F0710A.info.xres-1, fusion_F0710A.info.xy_reverse);
+ val_cut_max(fusion_F0710A.y1, fusion_F0710A.info.yres-1, fusion_F0710A.info.xy_reverse);
+ val_cut_max(fusion_F0710A.x2, fusion_F0710A.info.xres-1, fusion_F0710A.info.xy_reverse);
+ val_cut_max(fusion_F0710A.y2, fusion_F0710A.info.yres-1, fusion_F0710A.info.xy_reverse);
+
+ if(fusion_F0710A.tip1 == 1)
+ {
+ if(fusion_F0710A.tid1 == 1)
+ {
+ /* first point */
+ x1 = fusion_F0710A.x1;
+ y1 = fusion_F0710A.y1;
+ z1 = fusion_F0710A.z1;
+ save_points |= fusion_F0710A_SAVE_PT1;
+ }
+ else if(fusion_F0710A.tid1 == 2)
+ {
+ /* second point ABS_DISTANCE second point pressure, BTN_2 second point touch */
+ x2 = fusion_F0710A.x1;
+ y2 = fusion_F0710A.y1;
+ z2 = fusion_F0710A.z1;
+ save_points |= fusion_F0710A_SAVE_PT2;
+ }
+ }
+
+ if(fusion_F0710A.tip2 == 1)
+ {
+ if(fusion_F0710A.tid2 == 2)
+ {
+ /* second point ABS_DISTANCE second point pressure, BTN_2 second point touch */
+ x2 = fusion_F0710A.x2;
+ y2 = fusion_F0710A.y2;
+ z2 = fusion_F0710A.z2;
+ save_points |= fusion_F0710A_SAVE_PT2;
+ }
+ else if(fusion_F0710A.tid2 == 1)/* maybe this will never happen */
+ {
+ /* first point */
+ x1 = fusion_F0710A.x2;
+ y1 = fusion_F0710A.y2;
+ z1 = fusion_F0710A.z2;
+ save_points |= fusion_F0710A_SAVE_PT1;
+ }
+ }
+
+#ifdef CONFIG_ANDROID
+ if(z1)
+ {
+ input_report_abs(dev, ABS_MT_TRACKING_ID, 1);
+ input_report_abs(dev, ABS_MT_POSITION_X, x1);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y1);
+ }
+ input_mt_sync(dev);
+
+ if(z2)
+ {
+ input_report_abs(dev, ABS_MT_TRACKING_ID, 2);
+ input_report_abs(dev, ABS_MT_POSITION_X, x2);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y2);
+ }
+ input_mt_sync(dev);
+#else /* CONFIG_ANDROID */
+ input_report_abs(dev, ABS_MT_TOUCH_MAJOR, z1);
+ input_report_abs(dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_report_abs(dev, ABS_MT_POSITION_X, x1);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y1);
+ input_mt_sync(dev);
+ input_report_abs(dev, ABS_MT_TOUCH_MAJOR, z2);
+ input_report_abs(dev, ABS_MT_WIDTH_MAJOR, 2);
+ input_report_abs(dev, ABS_MT_POSITION_X, x2);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y2);
+ input_mt_sync(dev);
+#endif /* CONFIG_ANDROID */
+
+ input_report_abs(dev, ABS_X, x1);
+ input_report_abs(dev, ABS_Y, y1);
+ input_report_abs(dev, ABS_PRESSURE, z1);
+ input_report_key(dev, BTN_TOUCH, fusion_F0710A.tip1);
+
+ input_sync(dev);
+
+restore_irq:
+ enable_irq(fusion_F0710A.client->irq);
+
+ /* Clear fusion_F0710A interrupt */
+ fusion_F0710A_write_complete();
+}
+static DECLARE_WORK(fusion_F0710A_work, fusion_F0710A_wq);
+
+static irqreturn_t fusion_F0710A_interrupt(int irq, void *dev_id)
+{
+ disable_irq_nosync(fusion_F0710A.client->irq);
+
+ queue_work(fusion_F0710A.workq, &fusion_F0710A_work);
+
+ return IRQ_HANDLED;
+}
+
+const static u8* g_ver_product[4] = {
+ "10Z8", "70Z7", "43Z6", ""
+};
+
+static int fusion_F0710A_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+ struct fusion_f0710a_init_data *pdata = i2c->dev.platform_data;
+ int ret;
+ u8 ver_product, ver_id;
+ u32 version;
+
+ if (pdata == NULL)
+ {
+ dev_err(&i2c->dev, "No platform data for Fusion driver\n");
+ return -ENODEV;
+ }
+
+ /* Request pinmuxing, if necessary */
+ if (pdata->pinmux_fusion_pins != NULL)
+ {
+ ret = pdata->pinmux_fusion_pins();
+ if (ret < 0) {
+ dev_err(&i2c->dev, "muxing GPIOs failed\n");
+ return -ENODEV;
+ }
+ }
+
+ if ((gpio_request(pdata->gpio_int, "Fusion pen down interrupt") == 0) &&
+ (gpio_direction_input(pdata->gpio_int) == 0)) {
+ gpio_export(pdata->gpio_int, 0);
+ } else {
+ dev_warn(&i2c->dev, "Could not obtain GPIO for Fusion pen down\n");
+ return -ENODEV;
+ }
+
+ if ((gpio_request(pdata->gpio_reset, "Fusion reset") == 0) &&
+ (gpio_direction_output(pdata->gpio_reset, 1) == 0)) {
+
+ /* Generate a 0 => 1 edge explicitly, and wait for startup... */
+ gpio_set_value(pdata->gpio_reset, 0);
+ msleep(10);
+ gpio_set_value(pdata->gpio_reset, 1);
+ /* Wait for startup (up to 125ms according to datasheet) */
+ msleep(125);
+
+ gpio_export(pdata->gpio_reset, 0);
+ } else {
+ dev_warn(&i2c->dev, "Could not obtain GPIO for Fusion reset\n");
+ ret = -ENODEV;
+ goto bail0;
+ }
+
+ /* Use Pen Down GPIO as sampling interrupt */
+ i2c->irq = gpio_to_irq(pdata->gpio_int);
+
+ if(!i2c->irq)
+ {
+ dev_err(&i2c->dev, "fusion_F0710A irq < 0 \n");
+ ret = -ENOMEM;
+ goto bail1;
+ }
+
+ /* Attach the I2C client */
+ fusion_F0710A.client = i2c;
+ i2c_set_clientdata(i2c, &fusion_F0710A);
+
+ dev_info(&i2c->dev, "Touchscreen registered with bus id (%d) with slave address 0x%x\n",
+ i2c_adapter_id(fusion_F0710A.client->adapter), fusion_F0710A.client->addr);
+
+ /* Read out a lot of registers */
+ ret = fusion_F0710A_read_u8(fusion_F0710A_VIESION_INFO_LO);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "query failed: %d\n", ret);
+ goto bail1;
+ }
+ ver_product = (((u8)ret) & 0xc0) >> 6;
+ version = (10 + ((((u32)ret)&0x30) >> 4)) * 100000;
+ version += (((u32)ret)&0xf) * 1000;
+ /* Read out a lot of registers */
+ ret = fusion_F0710A_read_u8(fusion_F0710A_VIESION_INFO);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "query failed: %d\n", ret);
+ goto bail1;
+ }
+ ver_id = ((u8)(ret) & 0x6) >> 1;
+ version += ((((u32)ret) & 0xf8) >> 3) * 10;
+ version += (((u32)ret) & 0x1) + 1; /* 0 is build 1, 1 is build 2 */
+ dev_info(&i2c->dev, "version product %s(%d)\n", g_ver_product[ver_product] ,ver_product);
+ dev_info(&i2c->dev, "version id %s(%d)\n", ver_id ? "1.4" : "1.0", ver_id);
+ dev_info(&i2c->dev, "version series (%d)\n", version);
+
+ switch(ver_product)
+ {
+ case fusion_F0710A_VIESION_07: /* 7 inch */
+ fusion_F0710A.info.xres = fusion_F0710A07_XMAX;
+ fusion_F0710A.info.yres = fusion_F0710A07_YMAX;
+ fusion_F0710A.info.xy_reverse = fusion_F0710A07_REV;
+ break;
+ case fusion_F0710A_VIESION_43: /* 4.3 inch */
+ fusion_F0710A.info.xres = fusion_F0710A43_XMAX;
+ fusion_F0710A.info.yres = fusion_F0710A43_YMAX;
+ fusion_F0710A.info.xy_reverse = fusion_F0710A43_REV;
+ break;
+ default: /* fusion_F0710A_VIESION_10 10 inch */
+ fusion_F0710A.info.xres = fusion_F0710A10_XMAX;
+ fusion_F0710A.info.yres = fusion_F0710A10_YMAX;
+ fusion_F0710A.info.xy_reverse = fusion_F0710A10_REV;
+ break;
+ }
+
+ /* Register the input device. */
+ ret = fusion_F0710A_register_input();
+ if (ret < 0) {
+ dev_err(&i2c->dev, "can't register input: %d\n", ret);
+ goto bail1;
+ }
+
+ /* Create a worker thread */
+ fusion_F0710A.workq = create_singlethread_workqueue(DRV_NAME);
+ if (fusion_F0710A.workq == NULL) {
+ dev_err(&i2c->dev, "can't create work queue\n");
+ ret = -ENOMEM;
+ goto bail2;
+ }
+
+
+ /* Register for the interrupt and enable it. Our handler will
+ * start getting invoked after this call. */
+ ret = request_irq(i2c->irq, fusion_F0710A_interrupt, IRQF_TRIGGER_RISING,
+ i2c->name, &fusion_F0710A);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "can't get irq %d: %d\n", i2c->irq, ret);
+ goto bail3;
+ }
+ /* clear the irq first */
+ ret = fusion_F0710A_write_u8(fusion_F0710A_SCAN_COMPLETE, 0);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Clear irq failed: %d\n", ret);
+ goto bail4;
+ }
+
+ return 0;
+
+bail4:
+ free_irq(i2c->irq, &fusion_F0710A);
+
+bail3:
+ destroy_workqueue(fusion_F0710A.workq);
+ fusion_F0710A.workq = NULL;
+
+bail2:
+ input_unregister_device(fusion_F0710A.input);
+bail1:
+ gpio_free(pdata->gpio_reset);
+bail0:
+ gpio_free(pdata->gpio_int);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fusion_F0710A_suspend(struct device *dev)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+ disable_irq(i2c->irq);
+ flush_workqueue(fusion_F0710A.workq);
+
+ return 0;
+}
+
+static int fusion_F0710A_resume(struct device *dev)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+ enable_irq(i2c->irq);
+
+ return 0;
+}
+#endif
+
+static int fusion_F0710A_remove(struct i2c_client *i2c)
+{
+ struct fusion_f0710a_init_data *pdata = i2c->dev.platform_data;
+
+ gpio_free(pdata->gpio_int);
+ gpio_free(pdata->gpio_reset);
+ destroy_workqueue(fusion_F0710A.workq);
+ free_irq(i2c->irq, &fusion_F0710A);
+ input_unregister_device(fusion_F0710A.input);
+ i2c_set_clientdata(i2c, NULL);
+
+ dev_info(&i2c->dev, "driver removed\n");
+
+ return 0;
+}
+
+static struct i2c_device_id fusion_F0710A_id[] = {
+ {"fusion_F0710A", 0},
+ {},
+};
+
+static const struct dev_pm_ops fusion_F0710A_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(fusion_F0710A_suspend, fusion_F0710A_resume)
+};
+
+static struct i2c_driver fusion_F0710A_i2c_drv = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .pm = &fusion_F0710A_pm_ops,
+ },
+ .probe = fusion_F0710A_probe,
+ .remove = fusion_F0710A_remove,
+ .id_table = fusion_F0710A_id,
+ .address_list = normal_i2c,
+};
+
+static int __init fusion_F0710A_init( void )
+{
+ int ret;
+
+ memset(&fusion_F0710A, 0, sizeof(fusion_F0710A));
+
+ /* Probe for fusion_F0710A on I2C. */
+ ret = i2c_add_driver(&fusion_F0710A_i2c_drv);
+ if (ret < 0) {
+ printk(KERN_WARNING DRV_NAME " can't add i2c driver: %d\n", ret);
+ }
+
+ return ret;
+}
+
+static void __exit fusion_F0710A_exit( void )
+{
+ i2c_del_driver(&fusion_F0710A_i2c_drv);
+}
+module_init(fusion_F0710A_init);
+module_exit(fusion_F0710A_exit);
+
+MODULE_DESCRIPTION("fusion_F0710A Touchscreen Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/touchscreen/fusion_F0710A.h b/drivers/input/touchscreen/fusion_F0710A.h
new file mode 100644
index 000000000000..85f8210345a9
--- /dev/null
+++ b/drivers/input/touchscreen/fusion_F0710A.h
@@ -0,0 +1,87 @@
+/*
+ * "fusion_F0710A" touchscreen driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* I2C slave address */
+#define fusion_F0710A_I2C_SLAVE_ADDR 0x10
+
+/* I2C registers */
+#define fusion_F0710A_DATA_INFO 0x00
+
+/* First Point*/
+#define fusion_F0710A_POS_X1_HI 0x01 /* 16-bit register, MSB */
+#define fusion_F0710A_POS_X1_LO 0x02 /* 16-bit register, LSB */
+#define fusion_F0710A_POS_Y1_HI 0x03 /* 16-bit register, MSB */
+#define fusion_F0710A_POS_Y1_LO 0x04 /* 16-bit register, LSB */
+#define fusion_F0710A_FIR_PRESS 0X05
+#define fusion_F0710A_FIR_TIDTS 0X06
+
+/* Second Point */
+#define fusion_F0710A_POS_X2_HI 0x07 /* 16-bit register, MSB */
+#define fusion_F0710A_POS_X2_LO 0x08 /* 16-bit register, LSB */
+#define fusion_F0710A_POS_Y2_HI 0x09 /* 16-bit register, MSB */
+#define fusion_F0710A_POS_Y2_LO 0x0A /* 16-bit register, LSB */
+#define fusion_F0710A_SEC_PRESS 0x0B
+#define fusion_F0710A_SEC_TIDTS 0x0C
+
+#define fusion_F0710A_VIESION_INFO_LO 0X0E
+#define fusion_F0710A_VIESION_INFO 0X0F
+
+#define fusion_F0710A_RESET 0x10
+#define fusion_F0710A_SCAN_COMPLETE 0x11
+
+
+#define fusion_F0710A_VIESION_10 0
+#define fusion_F0710A_VIESION_07 1
+#define fusion_F0710A_VIESION_43 2
+
+/* fusion_F0710A 10 inch panel */
+#define fusion_F0710A10_XMAX 2275
+#define fusion_F0710A10_YMAX 1275
+#define fusion_F0710A10_REV 1
+
+/* fusion_F0710A 7 inch panel */
+#define fusion_F0710A07_XMAX 1500
+#define fusion_F0710A07_YMAX 900
+#define fusion_F0710A07_REV 0
+
+/* fusion_F0710A 4.3 inch panel */
+#define fusion_F0710A43_XMAX 900
+#define fusion_F0710A43_YMAX 500
+#define fusion_F0710A43_REV 0
+
+#define fusion_F0710A_SAVE_PT1 0x1
+#define fusion_F0710A_SAVE_PT2 0x2
+
+
+
+/* fusion_F0710A touch screen information */
+struct fusion_F0710A_info {
+ int xres; /* x resolution */
+ int yres; /* y resolution */
+ int xy_reverse; /* if need reverse in the x,y value x=xres-1-x, y=yres-1-y*/
+};
+
+struct fusion_F0710A_data {
+ struct fusion_F0710A_info info;
+ struct i2c_client *client;
+ struct workqueue_struct *workq;
+ struct input_dev *input;
+ u16 x1;
+ u16 y1;
+ u8 z1;
+ u8 tip1;
+ u8 tid1;
+ u16 x2;
+ u16 y2;
+ u8 z2;
+ u8 tip2;
+ u8 tid2;
+ u8 f_num;
+ u8 save_points;
+};
+
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index ae88e13c99ff..dbd94f3c957a 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -48,17 +48,6 @@
#define STMPE_IRQ_TOUCH_DET 0
-#define SAMPLE_TIME(x) ((x & 0xf) << 4)
-#define MOD_12B(x) ((x & 0x1) << 3)
-#define REF_SEL(x) ((x & 0x1) << 1)
-#define ADC_FREQ(x) (x & 0x3)
-#define AVE_CTRL(x) ((x & 0x3) << 6)
-#define DET_DELAY(x) ((x & 0x7) << 3)
-#define SETTLING(x) (x & 0x7)
-#define FRACTION_Z(x) (x & 0x7)
-#define I_DRIVE(x) (x & 0x1)
-#define OP_MODE(x) ((x & 0x7) << 1)
-
#define STMPE_TS_NAME "stmpe-ts"
#define XY_MASK 0xfff
@@ -118,6 +107,7 @@ static void stmpe_work(struct work_struct *work)
__stmpe_reset_fifo(ts->stmpe);
input_report_abs(ts->idev, ABS_PRESSURE, 0);
+ input_report_key(ts->idev, BTN_TOUCH, 0);
input_sync(ts->idev);
}
@@ -148,9 +138,17 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data)
y = ((data_set[1] & 0xf) << 8) | data_set[2];
z = data_set[3];
+#ifndef CONFIG_ANDROID
input_report_abs(ts->idev, ABS_X, x);
input_report_abs(ts->idev, ABS_Y, y);
+#else /* !CONFIG_ANDROID */
+ /* Hack: rotate touch for now due to missing calibration integration
+ Note: 12-bit touch resolution */
+ input_report_abs(ts->idev, ABS_X, 4096 - x);
+ input_report_abs(ts->idev, ABS_Y, 4096 - y);
+#endif /* !CONFIG_ANDROID */
input_report_abs(ts->idev, ABS_PRESSURE, z);
+ input_report_key(ts->idev, BTN_TOUCH, (z != 0));
input_sync(ts->idev);
/* flush the FIFO after we have read out our values. */
@@ -161,7 +159,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data)
STMPE_TSC_CTRL_TSC_EN, STMPE_TSC_CTRL_TSC_EN);
/* start polling for touch_det to detect release */
- schedule_delayed_work(&ts->work, HZ / 50);
+ schedule_delayed_work(&ts->work, HZ / 10);
return IRQ_HANDLED;
}
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index 5dbe73af2f8f..72e2abea2c28 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -54,6 +54,10 @@
#define WM_CORE_VERSION "1.00"
#define DEFAULT_PRESSURE 0xb0c0
+#ifdef CONFIG_MACH_COLIBRI_T20
+extern void *get_colibri_t20_audio_platform_data(void);
+#endif
+
/*
* Touchscreen absolute values
@@ -442,8 +446,18 @@ static int wm97xx_read_samples(struct wm97xx *wm)
"pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n",
data.x >> 12, data.x & 0xfff, data.y >> 12,
data.y & 0xfff, data.p >> 12, data.p & 0xfff);
+#ifndef CONFIG_ANDROID
input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff);
input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff);
+#else /* !CONFIG_ANDROID */
+ /* Hack: rotate touch for now due to missing calibration
+ integration
+ Note: 12-bit touch resolution */
+ input_report_abs(wm->input_dev, ABS_X, 4096 - (data.x & 0xfff));
+ input_report_abs(wm->input_dev, ABS_Y, 4096 - (data.y & 0xfff));
+#endif /* !CONFIG_ANDROID */
+
+
input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff);
input_report_key(wm->input_dev, BTN_TOUCH, 1);
input_sync(wm->input_dev);
@@ -640,7 +654,12 @@ static int wm97xx_probe(struct device *dev)
}
/* set up touch configuration */
+#ifdef CONFIG_ANDROID
+ /* Hack: rename due to idc parser having issues with spaces in names */
+ wm->input_dev->name = "wm97xx-ts";
+#else /* CONFIG_ANDROID */
wm->input_dev->name = "wm97xx touchscreen";
+#endif /* CONFIG_ANDROID */
wm->input_dev->phys = "wm97xx";
wm->input_dev->open = wm97xx_ts_input_open;
wm->input_dev->close = wm97xx_ts_input_close;
@@ -671,7 +690,13 @@ static int wm97xx_probe(struct device *dev)
}
platform_set_drvdata(wm->battery_dev, wm);
wm->battery_dev->dev.parent = dev;
+
+#if defined(CONFIG_MACH_COLIBRI_T20) && !defined(CONFIG_ANDROID)
+ wm->battery_dev->dev.platform_data = get_colibri_t20_audio_platform_data();
+#else
wm->battery_dev->dev.platform_data = pdata;
+#endif
+
ret = platform_device_add(wm->battery_dev);
if (ret < 0)
goto batt_reg_err;
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index dfff30255a92..0fe628f5912d 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -60,7 +60,6 @@ config VIDEOBUF2_VMALLOC
select VIDEOBUF2_MEMOPS
tristate
-
config VIDEOBUF2_DMA_SG
#depends on HAS_DMA
select VIDEOBUF2_CORE
@@ -797,6 +796,12 @@ config SOC_CAMERA_IMX074
help
This driver supports IMX074 cameras from Sony
+config SOC_CAMERA_MAX9526
+ tristate "max9526 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports MAX9526 video decoders from Maxim Integrated
+
config SOC_CAMERA_MT9M001
tristate "mt9m001 support"
depends on SOC_CAMERA && I2C
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ce79916258ef..28362059e105 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
+obj-$(CONFIG_SOC_CAMERA_MAX9526) += max9526.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index d2138d06bcad..14b48edb39b2 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -27,13 +27,20 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
#include <linux/mutex.h>
#define DRIVER_NAME "adv7180"
#define ADV7180_INPUT_CONTROL_REG 0x00
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN1 0x00
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN2 0x01
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN3 0x02
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN4 0x03
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN5 0x04
+#define ADV7180_INPUT_CONTROL_COMPOSITE_IN6 0x05
#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00
-#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
+#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_M_SECAM 0x10
#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20
#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30
#define ADV7180_INPUT_CONTROL_NTSC_J 0x40
@@ -71,7 +78,8 @@
#define ADV7180_STATUS1_AUTOD_SECAM_525 0x70
#define ADV7180_IDENT_REG 0x11
-#define ADV7180_ID_7180 0x18
+#define ADV7180_ID_7180 0x1C /* 64-lead and 40-lead models only */
+#define ADV7180_ID2_7180 0x1E /* 48-lead and 32-lead devices only */
#define ADV7180_ICONF1_ADI 0x40
#define ADV7180_ICONF1_ACTIVE_LOW 0x01
@@ -97,6 +105,7 @@ struct adv7180_state {
int irq;
v4l2_std_id curr_norm;
bool autodetect;
+ int active_input;
};
static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
@@ -224,14 +233,18 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
if (std == V4L2_STD_ALL) {
ret = i2c_smbus_write_byte_data(client,
ADV7180_INPUT_CONTROL_REG,
- ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
+ ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM |
+ (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input));
if (ret < 0)
goto out;
__adv7180_status(client, NULL, &state->curr_norm);
state->autodetect = true;
} else {
- ret = v4l2_std_to_adv7180(std);
+ ret = v4l2_std_to_adv7180(std) |
+ (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input);
if (ret < 0)
goto out;
@@ -249,19 +262,99 @@ out:
return ret;
}
+static int adv7180_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ return 0;
+}
+
+/* Request bus settings on camera side */
+static unsigned long adv7180_query_bus_param(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static enum v4l2_mbus_pixelcode adv7180_codes[] = {
+ V4L2_MBUS_FMT_YUYV8_2X8,
+};
+
+static int adv7180_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ enum v4l2_colorspace cspace;
+ enum v4l2_mbus_pixelcode code = mf->code;
+// struct i2c_client *client = v4l2_get_subdevdata(sd);
+// u8 status1;
+
+// status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
+// printk(KERN_ERR "*********************************** status1 = 0x%02x\n", status1);
+
+ switch (code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ cspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mf->code = code;
+ mf->colorspace = cspace;
+
+ return adv7180_s_std(sd, V4L2_STD_ALL);
+}
+
+static int adv7180_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ mf->field = V4L2_FIELD_INTERLACED_TB;
+ mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+ // PAL
+ mf->width = 720;
+ mf->height = 576;
+
+ return 0;
+}
+
+static int adv7180_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(adv7180_codes))
+ return -EINVAL;
+
+ *code = adv7180_codes[index];
+
+ return 0;
+}
+
+static struct soc_camera_ops adv7180_ops = {
+ .set_bus_param = adv7180_set_bus_param,
+ .query_bus_param = adv7180_query_bus_param,
+};
+
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
- .querystd = adv7180_querystd,
- .g_input_status = adv7180_g_input_status,
+ .s_mbus_fmt = adv7180_s_fmt,
+ .try_mbus_fmt = adv7180_try_fmt,
+ .enum_mbus_fmt = adv7180_enum_fmt,
+ .querystd = adv7180_querystd,
+ .g_input_status = adv7180_g_input_status,
};
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
- .g_chip_ident = adv7180_g_chip_ident,
- .s_std = adv7180_s_std,
+ .g_chip_ident = adv7180_g_chip_ident,
+ .s_std = adv7180_s_std,
};
-static const struct v4l2_subdev_ops adv7180_ops = {
- .core = &adv7180_core_ops,
- .video = &adv7180_video_ops,
+static const struct v4l2_subdev_ops adv7180_subdev_ops = {
+ .core = &adv7180_core_ops,
+ .video = &adv7180_video_ops,
};
static void adv7180_work(struct work_struct *work)
@@ -297,6 +390,36 @@ static irqreturn_t adv7180_irq(int irq, void *devid)
return IRQ_HANDLED;
}
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i) {
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct adv7180_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 val;
+
+ if (i < 6) {
+ state->active_input = i;
+ val = i2c_smbus_read_byte_data(client,
+ ADV7180_INPUT_CONTROL_REG);
+ val &= 0xf0;
+ val |= (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input);
+ return i2c_smbus_write_byte_data(client,
+ ADV7180_INPUT_CONTROL_REG, val);
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) {
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct adv7180_state *state = to_state(sd);
+
+ *i = state->active_input;
+
+ return 0;
+}
+
/*
* Generic i2c probe
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
@@ -306,8 +429,11 @@ static __devinit int adv7180_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct adv7180_state *state;
+ struct soc_camera_device *icd = client->dev.platform_data;
struct v4l2_subdev *sd;
+ u8 ident;
int ret;
+ struct v4l2_ioctl_ops *ops;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -322,17 +448,25 @@ static __devinit int adv7180_probe(struct i2c_client *client,
goto err;
}
+ ident = i2c_smbus_read_byte_data(client, ADV7180_IDENT_REG);
+ WARN_ON((ident != ADV7180_ID_7180) && (ident != ADV7180_ID2_7180));
+ v4l_info(client, "ident reg is 0x%02x\n", ident);
+
state->irq = client->irq;
INIT_WORK(&state->work, adv7180_work);
mutex_init(&state->mutex);
state->autodetect = true;
+ state->active_input = 0; // input 1
sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
+ v4l2_i2c_subdev_init(sd, client, &adv7180_subdev_ops);
+ icd->ops = &adv7180_ops;
/* Initialize adv7180 */
/* Enable autodetection */
ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
- ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
+ ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM |
+ (ADV7180_INPUT_CONTROL_COMPOSITE_IN1 +
+ state->active_input));
if (ret < 0)
goto err_unreg_subdev;
@@ -393,6 +527,15 @@ static __devinit int adv7180_probe(struct i2c_client *client,
goto err_unreg_subdev;
}
+ /*
+ * this is the only way to support more than one input as soc_camera
+ * assumes in its own vidioc_s(g)_input implementation that only one
+ * input is present we have to override that with our own handlers.
+ */
+ ops = (struct v4l2_ioctl_ops*)icd->vdev->ioctl_ops;
+ ops->vidioc_s_input = &vidioc_s_input;
+ ops->vidioc_g_input = &vidioc_g_input;
+
return 0;
err_unreg_subdev:
@@ -432,7 +575,7 @@ static const struct i2c_device_id adv7180_id[] = {
{},
};
-MODULE_DEVICE_TABLE(i2c, adv7180_id);
+//MODULE_DEVICE_TABLE(i2c, adv7180_id);
static struct i2c_driver adv7180_driver = {
.driver = {
@@ -460,4 +603,3 @@ module_exit(adv7180_exit);
MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
MODULE_AUTHOR("Mocean Laboratories");
MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/media/video/max9526.c b/drivers/media/video/max9526.c
new file mode 100644
index 000000000000..1f13dcb29c5a
--- /dev/null
+++ b/drivers/media/video/max9526.c
@@ -0,0 +1,1102 @@
+/*
+ * drivers/media/video/max9526.c
+ *
+ * MAXIM MAX9526 decoder driver
+ *
+ * Copyright (c) 2011 Ming-Yao Chen <mychen0518@gmail.com>
+ * (based on tvp514x.c)
+ *
+ * Copyright (c) 2013 Ant Micro <www.antmicro.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ioctl.h>
+
+/*MODULE NAME*/
+#define MAX9526_MODULE_NAME "max9526"
+
+/*Private macros for MAX9526*/
+
+#define LOCK_RETRY_DELAY (200)
+#define LOCK_RETRY_COUNT (5)
+#define I2C_RETRY_COUNT (5)
+
+
+ /* registers */
+#define REG_STATUS_0 0x00
+#define REG_STATUS_1 0x01
+#define REG_IRQMASK_0 0x02
+#define REG_IRQMASK_1 0x03
+#define REG_STANDARD_SELECT_SHUTDOWN_CONTROL 0x04
+#define REG_CONTRAST 0x05
+#define REG_BRIGHTNESS 0x06
+#define REG_HUE 0x07
+#define REG_SATURATION 0x08
+#define REG_VIDEO_INPUT_SELECT_AND_CLAMP 0x09
+#define REG_GAIN_CONTROL 0x0A
+#define REG_COLOR_KILL 0x0B
+#define REG_OUTPUT_TEST_SIGNAL 0x0C
+#define REG_CLOCK_AND_OUTPUT 0x0D
+#define REG_PLL_CONTROL 0x0E
+#define REG_MISCELLANEOUS 0x0F
+
+#define PAL_NUM_ACTIVE_PIXELS (720)
+#define PAL_NUM_ACTIVE_LINES (576)
+
+#define NTSC_NUM_ACTIVE_PIXELS (720)
+#define NTSC_NUM_ACTIVE_LINES (480)
+
+#define REG_VIDEO_INPUT_SELECT_IN1 0x00
+#define REG_VIDEO_INPUT_SELECT_IN2 0x40
+#define REG_VIDEO_INPUT_SELECT_AUTO 0x80
+
+
+struct max9526_reg {
+ u8 token;
+ u8 reg;
+ u32 val;
+};
+
+enum max9526_tokens {
+ TOK_TERM,
+ TOK_SKIP,
+ TOK_DELAY,
+ TOK_WRITE,
+};
+
+enum {
+ VIDEO_STDSEL_NTSC_M_BIT,
+ VIDEO_STDSEL_PAL_BGHID_BIT,
+};
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("MAX9526 linux decoder driver");
+MODULE_LICENSE("GPL");
+
+
+/* enum max9526_std - enum for supported standards*/
+
+enum max9526_std {
+ STD_NTSC_MJ = 0,
+ STD_PAL_BDGHIN,
+ STD_INVALID
+};
+
+
+/**
+ * struct max9526_std_info - Structure to store standard informations
+ * @width: Line width in pixels
+ * @height:Number of active lines
+ * @video_std: Value to write in REG_VIDEO_STD register
+ * @standard: v4l2 standard structure information
+ */
+
+
+struct max9526_std_info {
+ unsigned long width;
+ unsigned long height;
+ u8 video_std;
+ struct v4l2_standard standard;
+};
+
+// TODO: redo this
+static const struct max9526_reg max9526_reg_list_default[] = {
+ {TOK_SKIP , REG_STATUS_0, 0x84},
+ {TOK_SKIP , REG_STATUS_1, 0x40},
+ {TOK_SKIP , REG_IRQMASK_0, 0x00},
+ {TOK_SKIP , REG_IRQMASK_1, 0x00},
+ /*Standard Select, Shutdown, and Control Register*/
+ {TOK_WRITE, REG_STANDARD_SELECT_SHUTDOWN_CONTROL, 0x10}, // was 0x10 (autodetect), 0x0=PAL, 0x40=NTSC
+ {TOK_SKIP, REG_CONTRAST, 0x80},
+ {TOK_SKIP, REG_BRIGHTNESS, 0x00},
+ {TOK_SKIP, REG_HUE, 0x80},
+ {TOK_SKIP, REG_SATURATION, 0x88},
+ {TOK_WRITE, REG_VIDEO_INPUT_SELECT_AND_CLAMP, 0x80}, // auto-select
+ // between input 1 and 2
+ {TOK_SKIP, REG_GAIN_CONTROL, 0x00},
+ {TOK_SKIP, REG_COLOR_KILL, 0x23},
+ {TOK_WRITE, REG_OUTPUT_TEST_SIGNAL, 0x03}, // select 100% color bars
+ {TOK_WRITE, REG_CLOCK_AND_OUTPUT, 0x04}, // select HSVS
+ {TOK_SKIP, REG_PLL_CONTROL, 0x03},
+ {TOK_SKIP, REG_MISCELLANEOUS, 0x18},
+ {TOK_TERM, 0, 0},
+};
+
+
+//static struct max9526_reg max9526_reg_list_default[0x11];
+
+/*MAX9526 default register values*/
+
+static int max9526_s_stream(struct v4l2_subdev *sd, int enable);
+
+/**
+ * struct max9526_decoder - MAX9526 decoder object
+ * @sd: Subdevice Slave handle
+ * @max9526_regs: copy of hw's regs with preset values.
+ * @pdata: Board specific
+ * @ver: Chip version
+ * @streaming: MAX9526 decoder streaming - enabled or disabled.
+ * @pix: Current pixel format
+ * @num_fmts: Number of formats
+ * @fmt_list: Format list
+ * @current_std: Current standard
+ * @num_stds: Number of standards
+ * @std_list: Standards list
+ * @input: Input routing at chip level
+ * @output: Output routing at chip level
+ */
+struct max9526_decoder {
+ struct v4l2_subdev sd;
+ struct max9526_reg max9526_regs[ARRAY_SIZE(max9526_reg_list_default)];
+ const struct max9526_platform_data *pdata;
+
+ int ver;
+ int streaming;
+
+ struct v4l2_pix_format pix;
+ int num_fmts;
+ const struct v4l2_fmtdesc *fmt_list;
+
+ enum max9526_std current_std;
+ int num_stds;
+ struct max9526_std_info *std_list;
+ /* Input and Output Routing parameters */
+ u32 input;
+ u32 output;
+
+ int active_input;
+};
+
+/**
+ * List of image formats supported by max9526 decoder
+ * Currently we are using 8 bit mode only, but can be
+ * extended to 10/20 bit mode.
+ */
+static const struct v4l2_fmtdesc max9526_fmt_list[] = {
+ {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .flags = 0,
+ .description = "8-bit YUYV 4:2:2 Format",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .index = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .flags = 0,
+ .description = "8-bit UYVY 4:2:2 Format",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+};
+
+/**
+ * Supported standards -
+ *
+ * Currently supports two standards only, need to add support for rest of the
+ * modes, like SECAM, etc...
+ */
+static struct max9526_std_info max9526_std_list[] = {
+ /* Standard: STD_NTSC_MJ */
+ [STD_NTSC_MJ] = {
+ .width = NTSC_NUM_ACTIVE_PIXELS,
+ .height = NTSC_NUM_ACTIVE_LINES,
+ .video_std = VIDEO_STDSEL_NTSC_M_BIT,
+ .standard = {
+ .index = 0,
+ .id = V4L2_STD_NTSC,
+ .name = "NTSC",
+ .frameperiod = {1001, 30000},
+ .framelines = 525
+ },
+ /* Standard: STD_PAL_BDGHIN */
+ },
+ [STD_PAL_BDGHIN] = {
+ .width = PAL_NUM_ACTIVE_PIXELS,
+ .height = PAL_NUM_ACTIVE_LINES,
+ .video_std = VIDEO_STDSEL_PAL_BGHID_BIT,
+ .standard = {
+ .index = 1,
+ .id = V4L2_STD_PAL,
+ .name = "PAL",
+ .frameperiod = {1, 25},
+ .framelines = 625
+ },
+ },
+ /* Standard: need to add for additional standard */
+};
+
+static inline struct max9526_decoder *to_decoder(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct max9526_decoder, sd);
+}
+
+/**
+ * max9526_read_reg() - Read a value from a register in an MAX9526.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: max9526 register address
+ *
+ * Returns value read if successful, or non-zero (-1) otherwise.
+ */
+static int max9526_read_reg(struct v4l2_subdev *sd, u8 reg)
+{
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+read_again:
+
+ err = i2c_smbus_read_byte_data(client, reg);
+ if (err < 0) {
+ if (retry <= I2C_RETRY_COUNT) {
+ v4l2_warn(sd, "Read: retry ... %d\n", retry);
+ retry++;
+ msleep_interruptible(10);
+ goto read_again;
+ }
+ }
+
+ return err;
+}
+
+#if 0
+/**
+ * dump_reg() - dump the register content of MAX9526.
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: MAX9526 register address
+ */
+static void dump_reg(struct v4l2_subdev *sd, u8 reg)
+{
+ u32 val;
+
+ val = max9526_read_reg(sd, reg);
+ v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val);
+}
+#endif
+
+/**
+ * max9526_write_reg() - Write a value to a register in MAX9526
+ * @sd: ptr to v4l2_subdev struct
+ * @reg: MAX9526 register address
+ * @val: value to be written to the register
+ *
+ * Write a value to a register in an MAX9526 decoder device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int max9526_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+ int err, retry = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+write_again:
+
+ err = i2c_smbus_write_byte_data(client, reg, val);
+ if (err) {
+ if (retry <= I2C_RETRY_COUNT) {
+ v4l2_warn(sd, "Write: retry ... %d\n", retry);
+ retry++;
+ msleep_interruptible(10);
+ goto write_again;
+ }
+ }
+// if (!err) {
+// v4l2_warn(sd, "max9526: wrote %X to register %X.\n", val, reg);
+// }
+ return err;
+}
+
+
+/**
+ * max9526_write_regs() : Initializes a list of MAX9526 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @reglist: list of MAX9526 registers and values
+ *
+ * Initializes a list of MAX9526 registers: token is state flag
+ * if token is TOK_TERM, then entire write operation terminates
+ * if token is TOK_DELAY, then a delay of 'val' msec is introduced
+ * if token is TOK_SKIP, then the register write is skipped
+ * if token is TOK_WRITE, then the register write is performed
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int max9526_write_regs(struct v4l2_subdev *sd,
+ const struct max9526_reg reglist[])
+{
+ int err;
+ const struct max9526_reg *next = reglist;
+ for (; next->token != TOK_TERM; next++) {
+ if (next->token == TOK_DELAY) {
+ msleep(next->val);
+ continue;
+ }
+
+ if (next->token == TOK_SKIP)
+ continue;
+
+ err = max9526_write_reg(sd, next->reg, (u8) next->val);
+ if (err) {
+ v4l2_err(sd, "Write failed. Err[%d]\n", err);
+ return err;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * max9526_get_current_std() : Get the current standard detected by max9526
+ * @sd: ptr to v4l2_subdev struct
+ *
+ * Get current standard detected by MAX9526, STD_INVALID if there is no
+ * standard detected.
+ */
+static enum max9526_std max9526_get_current_std(struct v4l2_subdev *sd)
+{
+ u8 std, std_status;
+
+ std = max9526_read_reg(sd, REG_STANDARD_SELECT_SHUTDOWN_CONTROL);
+
+ std_status = std>>5;
+ switch (std_status) {
+ case VIDEO_STDSEL_NTSC_M_BIT:
+ return STD_NTSC_MJ;
+
+ case VIDEO_STDSEL_PAL_BGHID_BIT:
+ return STD_PAL_BDGHIN;
+
+ default:
+ return STD_INVALID;
+ }
+
+ return STD_INVALID;
+}
+
+
+/**
+ * max9526_configure() - Configure the MAX9526 registers
+ * @sd: ptr to v4l2_subdev struct
+ * @decoder: ptr to max9526_decoder structure
+ *
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int max9526_configure(struct v4l2_subdev *sd, struct max9526_decoder *decoder)
+{
+ int err;
+
+ /* common register initialization */
+ err =
+ max9526_write_regs(sd, decoder->max9526_regs);
+ if (err)
+ return err;
+
+// if (debug)
+// max9526_reg_dump(sd);
+
+ return 0;
+}
+
+
+/**
+ * max9526_querystd() - V4L2 decoder interface handler for querystd
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @std_id: standard V4L2 std_id ioctl enum
+ *
+ * Returns the current standard detected by MAX9526. If no active input is
+ * detected, returns -EINVAL
+ */
+static int max9526_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
+{
+ struct max9526_decoder *decoder = to_decoder(sd);
+ enum max9526_std current_std;
+ //enum max9526_input input_sel;
+ //u8 sync_lock_status, lock_mask;
+ //int err;
+
+ if (std_id == NULL)
+ return -EINVAL;
+
+ msleep(LOCK_RETRY_DELAY);
+
+ /* get the current standard */
+ current_std = max9526_get_current_std(sd);
+ if (current_std == STD_INVALID)
+ return -EINVAL;
+
+ decoder->current_std = current_std;
+ *std_id = decoder->std_list[current_std].standard.id;
+
+// v4l2_dbg(1, debug, sd, "Current STD: %s",
+// decoder->std_list[current_std].standard.name);
+ return 0;
+}
+
+/**
+ * max9526_s_std() - V4L2 decoder interface handler for s_std
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @std_id: standard V4L2 v4l2_std_id ioctl enum
+ *
+ * If std_id is supported, sets the requested standard. Otherwise, returns
+ * -EINVAL
+ */
+static int max9526_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
+{
+ struct max9526_decoder *decoder = to_decoder(sd);
+ int err, i;
+
+ for (i = 0; i < decoder->num_stds; i++)
+ if (std_id & decoder->std_list[i].standard.id)
+ break;
+
+ if ((i == decoder->num_stds) || (i == STD_INVALID))
+ return -EINVAL;
+
+ err = max9526_write_reg(sd, REG_STANDARD_SELECT_SHUTDOWN_CONTROL,
+ decoder->std_list[i].video_std);
+ if (err)
+ return err;
+
+ decoder->current_std = i;
+ decoder->max9526_regs[REG_STANDARD_SELECT_SHUTDOWN_CONTROL].val =
+ decoder->std_list[i].video_std;
+
+// v4l2_dbg(1, debug, sd, "Standard set to: %s",
+// decoder->std_list[i].standard.name);
+ return 0;
+}
+
+/**
+ * max9526_s_routing() - V4L2 decoder interface handler for s_routing
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @input: input selector for routing the signal
+ * @output: output selector for routing the signal
+ * @config: config value. Not used
+ *
+ * If index is valid, selects the requested input. Otherwise, returns -EINVAL if
+ * the input is not supported or there is no active signal present in the
+ * selected input.
+ */
+static int max9526_s_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
+{
+ //struct max9526_decoder *decoder = to_decoder(sd);
+
+ /*
+ * For the sequence streamon -> streamoff and again s_input, most of
+ * the time it fails to lock the signal, since streamoff puts MAX9526
+ * into power off state which leads to failure in sub-sequent s_input.
+ */
+ max9526_s_stream(sd, 1);
+ return 0;
+}
+
+
+/**
+ * max9526_queryctrl() - V4L2 decoder interface handler for queryctrl
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @qctrl: standard V4L2 v4l2_queryctrl structure
+ *
+ * If the requested control is supported, returns the control information.
+ * Otherwise, returns -EINVAL if the control is not supported.
+ */
+static int
+max9526_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
+{
+ int err = -EINVAL;
+
+ if (qctrl == NULL)
+ return err;
+
+ switch (qctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ /* Brightness supported is (0-255), */
+ err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+ break;
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ /**
+ * Saturation and Contrast supported is -
+ * Contrast: 0 - 255 (Default - 128)
+ * Saturation: 0 - 255 (Default - 128)
+ */
+ err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+ break;
+ case V4L2_CID_HUE:
+ /* Hue Supported is -
+ * Hue - -180 - +180 (Default - 0, Step - +180)
+ */
+ err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ /**
+ * Auto Gain supported is -
+ * 0 - 1 (Default - 1)
+ */
+ err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+ break;
+ default:
+ v4l2_err(sd, "invalid control id %d\n", qctrl->id);
+ return err;
+ }
+
+// v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d",
+// qctrl->name, qctrl->minimum, qctrl->maximum,
+// qctrl->default_value);
+
+ return err;
+}
+
+
+/**
+ * max9526_g_ctrl() - V4L2 decoder interface handler for g_ctrl
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @ctrl: pointer to v4l2_control structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the decoder. Otherwise, returns -EINVAL if the control is not
+ * supported.
+ */
+static int
+max9526_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct max9526_decoder *decoder = to_decoder(sd);
+
+ if (ctrl == NULL)
+ return -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = decoder->max9526_regs[REG_BRIGHTNESS].val;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = decoder->max9526_regs[REG_CONTRAST].val;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = decoder->max9526_regs[REG_SATURATION].val;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = decoder->max9526_regs[REG_HUE].val;
+ if (ctrl->value == 0x7F)
+ ctrl->value = 180;
+ else if (ctrl->value == 0x80)
+ ctrl->value = -180;
+ else
+ ctrl->value = 0;
+
+ break;
+ default:
+ v4l2_err(sd, "invalid control id %d\n", ctrl->id);
+ return -EINVAL;
+ }
+
+// v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d",
+// ctrl->id, ctrl->value);
+ return 0;
+}
+
+/**
+ * max9526_s_ctrl() - V4L2 decoder interface handler for s_ctrl
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @ctrl: pointer to v4l2_control structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW. Otherwise, returns -EINVAL if the control is not supported.
+ */
+static int
+max9526_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct max9526_decoder *decoder = to_decoder(sd);
+ int err = -EINVAL, value;
+
+ if (ctrl == NULL)
+ return err;
+
+ value = ctrl->value;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ v4l2_err(sd, "invalid brightness setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+ err = max9526_write_reg(sd, REG_BRIGHTNESS,
+ value);
+ if (err)
+ return err;
+
+ decoder->max9526_regs[REG_BRIGHTNESS].val = value;
+ break;
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ v4l2_err(sd, "invalid contrast setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+ err = max9526_write_reg(sd, REG_CONTRAST, value);
+ if (err)
+ return err;
+
+ decoder->max9526_regs[REG_CONTRAST].val = value;
+ break;
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ v4l2_err(sd, "invalid saturation setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+ err = max9526_write_reg(sd, REG_SATURATION, value);
+ if (err)
+ return err;
+
+ decoder->max9526_regs[REG_SATURATION].val = value;
+ break;
+ case V4L2_CID_HUE:
+ if (value == 180)
+ value = 0x7F;
+ else if (value == -180)
+ value = 0x80;
+ else if (value == 0)
+ value = 0;
+ else {
+ v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+ err = max9526_write_reg(sd, REG_HUE, value);
+ if (err)
+ return err;
+
+ decoder->max9526_regs[REG_HUE].val = value;
+ break;
+ default:
+ v4l2_err(sd, "invalid control id %d\n", ctrl->id);
+ return err;
+ }
+
+// v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d",
+// ctrl->id, ctrl->value);
+
+ return err;
+}
+
+
+static int max9526_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ struct max9526_decoder *decoder = to_decoder(sd);
+
+ if (index < 0 || index >= decoder->num_fmts)
+ return -EINVAL;
+ switch (index) {
+ case 0:
+ *code = V4L2_MBUS_FMT_YUYV8_2X8;
+ break;
+ case 1:
+ *code = V4L2_MBUS_FMT_UYVY8_2X8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int max9526_try_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+/* pr_info("%s width:%d\n", __func__, mf->width);
+ pr_info("%s height:%d\n", __func__, mf->height);
+ pr_info("%s field:0x%X (V4L2_FIELD_NONE==0x%X)\n", __func__, mf->field, V4L2_FIELD_NONE);
+ pr_info("%s code:0x%X (V4L2_MBUS_FMT_YUYV8_2X8==0x%X)\n", __func__, mf->code, V4L2_MBUS_FMT_YUYV8_2X8);
+ pr_info("%s colorspace:0x%X (V4L2_COLORSPACE_SRGB==0x%X)\n", __func__, mf->colorspace, V4L2_COLORSPACE_SRGB);*/
+
+ if (mf->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ mf->width = PAL_NUM_ACTIVE_PIXELS;
+ mf->height = PAL_NUM_ACTIVE_LINES;
+ } else if (mf->code == V4L2_MBUS_FMT_YUYV8_2X8) {
+ mf->width = PAL_NUM_ACTIVE_PIXELS;
+ mf->height = PAL_NUM_ACTIVE_LINES;
+ }
+ mf->field = V4L2_FIELD_INTERLACED_TB;
+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ return 0;
+}
+
+
+/**
+ * max9526_g_parm() - V4L2 decoder interface handler for g_parm
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the decoder's video CAPTURE parameters.
+ */
+static int
+max9526_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct max9526_decoder *decoder = to_decoder(sd);
+ struct v4l2_captureparm *cparm;
+ enum max9526_std current_std;
+
+ if (a == NULL)
+ return -EINVAL;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ /* only capture is supported */
+ return -EINVAL;
+
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ /* get the current standard */
+ current_std = max9526_get_current_std(sd);
+ if (current_std == STD_INVALID)
+ return -EINVAL;
+
+ decoder->current_std = current_std;
+
+ cparm = &a->parm.capture;
+ cparm->capability = V4L2_CAP_TIMEPERFRAME;
+ cparm->timeperframe =
+ decoder->std_list[current_std].standard.frameperiod;
+
+ return 0;
+}
+
+
+/**
+ * max9526_s_parm() - V4L2 decoder interface handler for s_parm
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the decoder to use the input parameters, if possible. If
+ * not possible, returns the appropriate error code.
+ */
+static int
+max9526_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct max9526_decoder *decoder = to_decoder(sd);
+ struct v4l2_fract *timeperframe;
+ enum max9526_std current_std;
+
+ if (a == NULL)
+ return -EINVAL;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ /* only capture is supported */
+ return -EINVAL;
+
+ timeperframe = &a->parm.capture.timeperframe;
+
+ /* get the current standard */
+ current_std = max9526_get_current_std(sd);
+ if (current_std == STD_INVALID)
+ return -EINVAL;
+
+ decoder->current_std = current_std;
+
+ *timeperframe =
+ decoder->std_list[current_std].standard.frameperiod;
+
+ return 0;
+}
+
+/**
+ * max9526_s_stream() - V4L2 decoder i/f handler for s_stream
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @enable: streaming enable or disable
+ *
+ * Sets streaming to enable or disable, if possible.
+ */
+static int max9526_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ int err = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct max9526_decoder *decoder = to_decoder(sd);
+
+ if (decoder->streaming == enable)
+ return 0;
+
+ switch (enable) {
+ case 0:
+ {
+ decoder->streaming = enable;
+ break;
+ }
+ case 1:
+ {
+ struct max9526_reg *int_seq = (struct max9526_reg *)client->driver->id_table->driver_data;
+
+ err = max9526_write_regs(sd, int_seq);
+ if (err) {
+ v4l2_err(sd, "Unable to turn on decoder\n");
+ return err;
+ }
+ err = max9526_configure(sd, decoder);
+ if (err) {
+ v4l2_err(sd, "Unable to configure decoder\n");
+ return err;
+ }
+ decoder->streaming = enable;
+ break;
+ }
+ default:
+ err = -ENODEV;
+ break;
+ }
+
+ return err;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i) {
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct max9526_decoder *decoder = to_decoder(sd);
+ u8 val;
+
+ if (i < 3) {
+ decoder->active_input = i;
+ switch (decoder->active_input) {
+ case 0:
+ val = REG_VIDEO_INPUT_SELECT_IN1;
+ break;
+ case 1:
+ val = REG_VIDEO_INPUT_SELECT_IN2;
+ break;
+ default:
+ val = REG_VIDEO_INPUT_SELECT_AUTO;
+ }
+ return max9526_write_reg(sd, REG_VIDEO_INPUT_SELECT_AND_CLAMP,
+ val);
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) {
+ struct soc_camera_device *icd = file->private_data;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct max9526_decoder *decoder = to_decoder(sd);
+
+ *i = decoder->active_input;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops max9526_core_ops = {
+ .queryctrl = max9526_queryctrl,
+ .g_ctrl = max9526_g_ctrl,
+ .s_ctrl = max9526_s_ctrl,
+ .s_std = max9526_s_std,
+};
+
+
+static int max9526_s_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+#if 0
+ pr_info("%s width:%d\n", __func__, mf->width);
+ pr_info("%s height:%d\n", __func__, mf->height);
+ pr_info("%s field:0x%X (V4L2_FIELD_NONE==0x%X)\n", __func__, mf->field, V4L2_FIELD_NONE);
+ pr_info("%s code:0x%X (V4L2_MBUS_FMT_YUYV8_2X8==0x%X)\n", __func__, mf->code, V4L2_MBUS_FMT_YUYV8_2X8);
+ pr_info("%s colorspace:0x%X (V4L2_COLORSPACE_SRGB==0x%X)\n", __func__, mf->colorspace, V4L2_COLORSPACE_SRGB);
+
+ mf->width = PAL_NUM_ACTIVE_PIXELS;
+ mf->height = PAL_NUM_ACTIVE_LINES;
+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+#endif
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops max9526_video_ops = {
+ .s_routing = max9526_s_routing,
+ .querystd = max9526_querystd,
+ .enum_mbus_fmt = max9526_enum_mbus_fmt,
+ .try_mbus_fmt = max9526_try_mbus_fmt,
+ .s_mbus_fmt = max9526_s_mbus_fmt,
+ .g_parm = max9526_g_parm,
+ .s_parm = max9526_s_parm,
+ .s_stream = max9526_s_stream,
+};
+
+/* Alter bus settings on camera side */
+static int max9526_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ return 0;
+}
+
+static unsigned long max9526_query_bus_param(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static struct soc_camera_ops max9526_soc_camera_ops = {
+ .set_bus_param = max9526_set_bus_param,
+ .query_bus_param = max9526_query_bus_param,
+ .num_controls = 0,
+};
+
+static const struct v4l2_subdev_ops max9526_ops = {
+ .core = &max9526_core_ops,
+ .video = &max9526_video_ops,
+};
+
+static struct max9526_decoder max9526_dev = {
+ .streaming = 0,
+
+ .fmt_list = max9526_fmt_list,
+ .num_fmts = ARRAY_SIZE(max9526_fmt_list),
+
+ .pix = {
+ /* Default to PAL 8-bit YUV 422 */
+ .width = PAL_NUM_ACTIVE_PIXELS,
+ .height = PAL_NUM_ACTIVE_LINES,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_INTERLACED_TB,
+ .bytesperline = PAL_NUM_ACTIVE_PIXELS * 2,
+ .sizeimage =
+ PAL_NUM_ACTIVE_PIXELS * 2 * PAL_NUM_ACTIVE_LINES,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ },
+
+ .current_std = STD_PAL_BDGHIN,
+ .std_list = max9526_std_list,
+ .num_stds = ARRAY_SIZE(max9526_std_list),
+
+ .active_input = 2, // auto-select between input 1 and 2
+};
+
+/**
+ * max9526_probe() - decoder driver i2c probe handler
+ * @client: i2c driver client device structure
+ * @id: i2c driver id table
+ *
+ * Register decoder as an i2c client device and V4L2
+ * device.
+ */
+
+static int max9526_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct max9526_decoder *decoder;
+ struct v4l2_subdev *sd;
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct v4l2_ioctl_ops *ops;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ if (!client->dev.platform_data) {
+ v4l2_err(client, "No platform data!!\n");
+ return -ENODEV;
+ }
+
+ decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+ if (!decoder)
+ return -ENOMEM;
+
+ /* Initialize the max9526_decoder with default configuration */
+ *decoder = max9526_dev;
+ /* Copy default register configuration */
+ memcpy(decoder->max9526_regs, max9526_reg_list_default,
+ sizeof(max9526_reg_list_default));
+
+ /* Copy board specific information here */
+ decoder->pdata = client->dev.platform_data;
+
+
+ /* Register with V4L2 layer as slave device */
+ sd = &decoder->sd;
+ v4l2_i2c_subdev_init(sd, client, &max9526_ops);
+
+ icd->ops = &max9526_soc_camera_ops;
+
+ /*
+ * This is the only way to support more than one input as soc_camera
+ * assumes in its own vidioc_s(g)_input implementation that only one
+ * input is present we have to override that with our own handlers.
+ */
+ ops = (struct v4l2_ioctl_ops*)icd->vdev->ioctl_ops;
+ ops->vidioc_s_input = &vidioc_s_input;
+ ops->vidioc_g_input = &vidioc_g_input;
+
+ v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
+
+ return 0;
+
+}
+
+
+/**
+ * max9526_remove() - decoder driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister decoder as an i2c client device and V4L2
+ * device. Complement of max9526_probe().
+ */
+static int max9526_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct max9526_decoder *decoder = to_decoder(sd);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(decoder);
+ return 0;
+}
+
+/**
+ * I2C Device Table -
+ *
+ * name - Name of the actual device/chip.
+ * driver_data - Driver data
+ */
+static const struct i2c_device_id max9526_id[] = {
+ {"max9526", (unsigned long)max9526_reg_list_default},
+};
+
+
+static struct i2c_driver max9526_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = MAX9526_MODULE_NAME,
+ },
+ .probe = max9526_probe,
+ .remove = max9526_remove,
+ .id_table = max9526_id,
+};
+
+static int __init max9526_init(void)
+{
+ return i2c_add_driver(&max9526_driver);
+}
+
+static void __exit max9526_exit(void)
+{
+ i2c_del_driver(&max9526_driver);
+}
+
+module_init(max9526_init);
+module_exit(max9526_exit);
diff --git a/drivers/media/video/tegra_v4l2_camera.c b/drivers/media/video/tegra_v4l2_camera.c
index 8f71d1702537..14a74cd6b7cc 100644
--- a/drivers/media/video/tegra_v4l2_camera.c
+++ b/drivers/media/video/tegra_v4l2_camera.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -14,7 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -23,13 +22,14 @@
#include <linux/nvhost.h>
#include <mach/iomap.h>
-#include <mach/powergate.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#include <media/videobuf2-dma-nvmap.h>
#include <media/tegra_v4l2_camera.h>
+#include <mach/powergate.h>
+
#include "dev.h"
#include "bus_client.h"
#include "host1x/host1x_syncpt.h"
@@ -37,18 +37,22 @@
#define TEGRA_CAM_DRV_NAME "vi"
#define TEGRA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
-#define TEGRA_SYNCPT_VI_WAIT_TIMEOUT 200
+static unsigned int internal_sync = 0;
+module_param(internal_sync, int, 0644);
+MODULE_PARM_DESC(internal_sync, "enable internal vsync and hsync decoded " \
+ "from data");
+
+#define TEGRA_SYNCPT_VI_WAIT_TIMEOUT 25
#define TEGRA_SYNCPT_CSI_WAIT_TIMEOUT 200
#define TEGRA_SYNCPT_RETRY_COUNT 10
-#define TEGRA_VIP_H_ACTIVE_START 0x98
-#define TEGRA_VIP_V_ACTIVE_START 0x10
+#define TEGRA_VIP_H_ACTIVE_START 0x8F //0x98
+#define TEGRA_VIP_V_ACTIVE_START 0x12 //0x10
/* SYNCPTs 12-17 are reserved for VI. */
#define TEGRA_VI_SYNCPT_VI NVSYNCPT_VI_ISP_2
-#define TEGRA_VI_SYNCPT_CSI_A NVSYNCPT_VI_ISP_3
-#define TEGRA_VI_SYNCPT_CSI_B NVSYNCPT_VI_ISP_4
+#define TEGRA_VI_SYNCPT_CSI NVSYNCPT_VI_ISP_3
/* Tegra CSI-MIPI registers. */
#define TEGRA_VI_OUT_1_INCR_SYNCPT 0x0000
@@ -235,7 +239,10 @@
#define TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME 0x08c8
#define TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME 0x08cc
#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x08d0
-#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0 0x08d4
+
+#define IS_INTERLACED ((pcdev->field == V4L2_FIELD_INTERLACED)\
+ || (pcdev->field == V4L2_FIELD_INTERLACED_BT)\
+ || (pcdev->field == V4L2_FIELD_INTERLACED_TB))
#define TC_VI_REG_RD(DEV, REG) readl(DEV->vi_base + REG)
#define TC_VI_REG_WT(DEV, REG, VAL) writel(VAL, DEV->vi_base + REG)
@@ -256,8 +263,6 @@
struct tegra_buffer {
struct vb2_buffer vb; /* v4l buffer must be first */
struct list_head queue;
- struct soc_camera_device *icd;
- int output_channel;
/*
* Various buffer addresses shadowed so we don't have to recalculate
@@ -269,21 +274,20 @@ struct tegra_buffer {
dma_addr_t start_addr;
dma_addr_t start_addr_u;
dma_addr_t start_addr_v;
+ void* virtual_addr;
};
struct tegra_camera_dev {
struct soc_camera_host ici;
+ struct soc_camera_device *icd;
struct nvhost_device *ndev;
+ struct tegra_camera_platform_data *pdata;
struct clk *clk_vi;
struct clk *clk_vi_sensor;
struct clk *clk_csi;
struct clk *clk_isp;
struct clk *clk_csus;
- struct clk *clk_sclk;
- struct clk *clk_emc;
-
- struct regulator *reg;
void __iomem *vi_base;
spinlock_t videobuf_queue_lock;
@@ -291,22 +295,16 @@ struct tegra_camera_dev {
struct vb2_buffer *active;
struct vb2_alloc_ctx *alloc_ctx;
enum v4l2_field field;
- int sequence_a;
- int sequence_b;
+ int sequence;
struct work_struct work;
struct mutex work_mutex;
u32 syncpt_vi;
- u32 syncpt_csi_a;
- u32 syncpt_csi_b;
+ u32 syncpt_csi;
/* Debug */
int num_frames;
- int enable_refcnt;
-
- /* CSI pad calibration flag */
- int cal_done;
};
static const struct soc_mbus_pixelfmt tegra_camera_formats[] = {
@@ -352,23 +350,6 @@ static const struct soc_mbus_pixelfmt tegra_camera_formats[] = {
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
},
-
- /* For RAW8 and RAW10 output, we always output 16-bit (2 bytes). */
- {
- .fourcc = V4L2_PIX_FMT_SBGGR8,
- .name = "Bayer 8 BGBG.. GRGR..",
- .bits_per_sample = 16,
- .packing = SOC_MBUS_PACKING_EXTEND16,
- .order = SOC_MBUS_ORDER_LE,
- },
- {
- .fourcc = V4L2_PIX_FMT_SBGGR10,
- .name = "Bayer 10 BGBG.. GRGR..",
- .bits_per_sample = 16,
- .packing = SOC_MBUS_PACKING_EXTEND16,
- .order = SOC_MBUS_ORDER_LE,
- },
-
};
static struct tegra_buffer *to_tegra_vb(struct vb2_buffer *vb)
@@ -378,13 +359,9 @@ static struct tegra_buffer *to_tegra_vb(struct vb2_buffer *vb)
static void tegra_camera_save_syncpts(struct tegra_camera_dev *pcdev)
{
- pcdev->syncpt_csi_a =
+ pcdev->syncpt_csi =
nvhost_syncpt_read_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_A);
-
- pcdev->syncpt_csi_b =
- nvhost_syncpt_read_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_B);
+ TEGRA_VI_SYNCPT_CSI);
pcdev->syncpt_vi =
nvhost_syncpt_read_ext(pcdev->ndev,
@@ -394,65 +371,60 @@ static void tegra_camera_save_syncpts(struct tegra_camera_dev *pcdev)
static void tegra_camera_incr_syncpts(struct tegra_camera_dev *pcdev)
{
nvhost_syncpt_cpu_incr_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_A);
-
- nvhost_syncpt_cpu_incr_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_B);
+ TEGRA_VI_SYNCPT_CSI);
nvhost_syncpt_cpu_incr_ext(pcdev->ndev,
TEGRA_VI_SYNCPT_VI);
}
-static void tegra_camera_capture_clean(struct tegra_camera_dev *pcdev)
+static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev,
+ int input_format,
+ int yuv_input_format)
{
- TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000);
+ struct soc_camera_device *icd = pcdev->icd;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_READONLY_STATUS, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_ESCAPE_MODE_DATA, 0x0);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x02000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL,
+ (yuv_input_format << 8) |
+ (input_format << 2));
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_CONTROL, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_COUNTER_0, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_COUNTER_1, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_COUNTER_2, 0x0);
-}
+ TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000004);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000004);
-static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd,
- u32 hdr)
-{
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
+ /* CSI-A H_ACTIVE and V_ACTIVE */
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_H_ACTIVE,
+ (icd->user_width << 16));
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_V_ACTIVE,
+ (icd->user_height << 16));
+ /* CSI A */
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_A_CONTROL, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILA_CONTROL0, 0x00000000);
+
TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_PAD_CONFIG0, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_PAD_CONFIG1, 0x00000000);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME, 0x0);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x02000000);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000);
- /* CSI-A H_ACTIVE and V_ACTIVE */
- TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_H_ACTIVE,
- (icd->user_width << 16));
- TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_V_ACTIVE,
- (icd->user_height << 16));
+ /* pad1s enabled, virtual channel ID 00 */
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0,
+ (0x1 << 16) | /* Output 1 pixel per clock */
+ (0x1e << 8) | /* If hdr shows wrong fmt, use YUV422 */
+ (0x1 << 7) | /* Check header CRC */
+ (0x1 << 6) | /* Use word count field in the header */
+ (0x1 << 5) | /* Look at data identifier byte in hdr */
+ (0x1 << 4)); /* Expect packet header */
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1,
0x1); /* Frame # for top field detect for interlaced */
@@ -466,27 +438,22 @@ static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev,
(0x100 << 4) | /* Wait 0x100 vi clks for timeout */
0x1); /* Enable line timeout */
- /* pad 0s enabled, virtual channel ID 00 */
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0,
- (0x1 << 16) | /* Output 1 pixel per clock */
- (hdr << 8) | /* If hdr shows wrong fmt, use right value */
- (0x1 << 7) | /* Check header CRC */
- (0x1 << 6) | /* Use word count field in the header */
- (0x1 << 5) | /* Look at data identifier byte in hdr */
- (0x1 << 4)); /* Expect packet header */
-
TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_A_CONTROL,
(0x3f << 16) | /* Skip packet threshold */
- (pdata->lanes - 1));
+ (pcdev->pdata->lanes - 1));
/* Use 0x00000022 for continuous clock mode. */
TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILA_CONTROL0,
- (pdata->continuous_clk << 5) |
+ (pcdev->pdata->continuous_clk << 5) |
0x5); /* Clock settle time */
TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END,
(0x1 << 8) | /* Enable continuous syncpt */
- TEGRA_VI_SYNCPT_CSI_A);
+ TEGRA_VI_SYNCPT_CSI);
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1,
+ (0x1 << 8) | /* Enable continuous syncpt */
+ TEGRA_VI_SYNCPT_VI);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CIL_COMMAND, 0x00020001);
@@ -494,37 +461,49 @@ static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev,
}
static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd,
- u32 hdr)
+ int input_format,
+ int yuv_input_format)
{
- struct tegra_camera_platform_data *pdata = icd->link->priv;
+ struct soc_camera_device *icd = pcdev->icd;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x04000000);
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL,
+ (yuv_input_format << 8) |
+ (input_format << 2));
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000008);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000008);
+
+ /* CSI-B H_ACTIVE and V_ACTIVE */
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_H_ACTIVE,
+ (icd->user_width << 16));
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_V_ACTIVE,
+ (icd->user_height << 16));
+
+ /* CSI B */
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_B_CONTROL, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILB_CONTROL0, 0x00000000);
+
TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_PAD_CONFIG0, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_PAD_CONFIG1, 0x00000000);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME, 0x0);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x04000000);
-
- /* CSI-B H_ACTIVE and V_ACTIVE */
- TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_H_ACTIVE,
- (icd->user_width << 16));
- TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_V_ACTIVE,
- (icd->user_height << 16));
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000);
- /* pad 0s enabled, virtual channel ID 00 */
+ /* pad1s enabled, virtual channel ID 00 */
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0,
(0x1 << 16) | /* Output 1 pixel per clock */
- (hdr << 8) | /* If hdr shows wrong fmt, use right value */
+ (0x1e << 8) | /* If hdr shows wrong fmt, use YUV422 */
(0x1 << 7) | /* Check header CRC */
(0x1 << 6) | /* Use word count field in the header */
(0x1 << 5) | /* Look at data identifier byte in hdr */
@@ -545,16 +524,20 @@ static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev,
TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_B_CONTROL,
(0x3f << 16) | /* Skip packet threshold */
- (pdata->lanes - 1));
+ (pcdev->pdata->lanes - 1));
/* Use 0x00000022 for continuous clock mode. */
TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILB_CONTROL0,
- (pdata->continuous_clk << 5) |
+ (pcdev->pdata->continuous_clk << 5) |
0x5); /* Clock settle time */
TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END,
(0x1 << 8) | /* Enable continuous syncpt */
- TEGRA_VI_SYNCPT_CSI_B);
+ TEGRA_VI_SYNCPT_CSI);
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1,
+ (0x1 << 8) | /* Enable continuous syncpt */
+ TEGRA_VI_SYNCPT_VI);
TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CIL_COMMAND, 0x00010002);
@@ -562,17 +545,22 @@ static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev,
}
static void tegra_camera_capture_setup_vip(struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd,
- u32 input_control)
+ int input_format,
+ int yuv_input_format)
{
+ struct soc_camera_device *icd = pcdev->icd;
TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL,
- (1 << 27) | /* field detect */
- (1 << 25) | /* hsync/vsync decoded from data (BT.656) */
+// (1 << 27) | /* field detect */
+ (0 << 28) | /* 1 == top field is even field, 00 == odd */
+ ((internal_sync == 1) << 25) | /* 1 == hsync/vsync decoded
+ internally from data
+ (BT.656) */
+ (yuv_input_format << 8) |
(1 << 1) | /* VIP_INPUT_ENABLE */
- input_control);
+ (input_format << 2));
TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000000);
@@ -580,180 +568,80 @@ static void tegra_camera_capture_setup_vip(struct tegra_camera_dev *pcdev,
/* VIP H_ACTIVE and V_ACTIVE */
TC_VI_REG_WT(pcdev, TEGRA_VI_VIP_H_ACTIVE,
(icd->user_width << 16) |
- TEGRA_VIP_H_ACTIVE_START);
+ (TEGRA_VIP_H_ACTIVE_START - ((internal_sync == 1)?1:0)));
TC_VI_REG_WT(pcdev, TEGRA_VI_VIP_V_ACTIVE,
- (icd->user_height << 16) |
+ ( ( IS_INTERLACED ? (icd->user_height/2) : (icd->user_height) ) << 16) |
TEGRA_VIP_V_ACTIVE_START);
/*
* For VIP, D9..D2 is mapped to the video decoder's P7..P0.
* Disable/mask out the other Dn wires.
*/
- TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INPUT_ENABLE, 0x000003fc);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INPUT_ENABLE, 0x000003fc | 0x6000); // D2..D9 + VSYNC + HSYNC
TC_VI_REG_WT(pcdev, TEGRA_VI_VI_DATA_INPUT_CONTROL, 0x000003fc);
TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INVERSION, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_VIP_VSYNC,
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1,
(0x1 << 8) | /* Enable continuous syncpt */
TEGRA_VI_SYNCPT_VI);
- TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, 0x00000004);
+// TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, 0x00000004);
}
-static int tegra_camera_capture_output_channel_setup(
- struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd)
+static void tegra_camera_capture_setup(struct tegra_camera_dev *pcdev)
{
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int port = pdata->port;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
+ struct soc_camera_device *icd = pcdev->icd;
const struct soc_camera_format_xlate *current_fmt = icd->current_fmt;
+ enum v4l2_mbus_pixelcode input_code = current_fmt->code;
u32 output_fourcc = current_fmt->host_fmt->fourcc;
- u32 output_format, output_control;
- struct tegra_buffer *buf = to_tegra_vb(pcdev->active);
+ int yuv_input_format = 0x0;
+ int input_format = 0x0; /* Default to YUV422 */
+ int yuv_output_format = 0x0;
+ int output_format = 0x3; /* Default to YUV422 */
+ int port = pcdev->pdata->port;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ int frame_count = 1;
+
+ switch (input_code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ yuv_input_format = 0x2;
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ yuv_input_format = 0x3;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ yuv_input_format = 0x0;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ yuv_input_format = 0x1;
+ break;
+ default:
+ BUG_ON(1);
+ }
switch (output_fourcc) {
case V4L2_PIX_FMT_UYVY:
- output_format = 0x3; /* Default to YUV422 */
+ yuv_output_format = 0x0;
break;
case V4L2_PIX_FMT_VYUY:
- output_format = (0x1 << 17) | 0x3;
+ yuv_output_format = 0x1;
break;
case V4L2_PIX_FMT_YUYV:
- output_format = (0x2 << 17) | 0x3;
+ yuv_output_format = 0x2;
break;
case V4L2_PIX_FMT_YVYU:
- output_format = (0x3 << 17) | 0x3;
+ yuv_output_format = 0x3;
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
output_format = 0x6; /* YUV420 planar */
break;
- case V4L2_PIX_FMT_SBGGR8:
- case V4L2_PIX_FMT_SBGGR10:
- /* Use second output channel for RAW8/RAW10 */
- buf->output_channel = 1;
-
- if (port == TEGRA_CAMERA_PORT_CSI_A)
- output_format = 0x7;
- else if (port == TEGRA_CAMERA_PORT_CSI_B)
- output_format = 0x8;
- else
- output_format = 0x9;
- break;
default:
- dev_err(&pcdev->ndev->dev, "Wrong output format %d\n",
- output_fourcc);
- return -EINVAL;
+ BUG_ON(1);
}
- output_control = (pdata->flip_v ? (0x1 << 20) : 0) |
- (pdata->flip_h ? (0x1 << 19) : 0) |
- output_format;
-
- if (buf->output_channel == 0) {
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
- output_control);
- /*
- * Set up frame size. Bits 31:16 are the number of lines, and
- * bits 15:0 are the number of pixels per line.
- */
- TC_VI_REG_WT(pcdev, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE,
- (icd->user_height << 16) | icd->user_width);
-
- /* First output memory enabled */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000);
-
- /* Set the number of frames in the buffer. */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_FIRST, 0x00000001);
-
- /* Set up buffer frame size. */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_FIRST,
- (icd->user_height << 16) | icd->user_width);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
- (icd->user_height * bytes_per_line));
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1,
- (0x1 << 8) | /* Enable continuous syncpt */
- TEGRA_VI_SYNCPT_VI);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000);
- } else if (buf->output_channel == 1) {
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_SECOND_OUTPUT_CONTROL,
- output_control);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_SECOND_OUTPUT_FRAME_SIZE,
- (icd->user_height << 16) | icd->user_width);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE_2, 0x00000000);
-
- /* Set the number of frames in the buffer. */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_SECOND, 0x00000001);
-
- /* Set up buffer frame size. */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_SECOND,
- (icd->user_height << 16) | icd->user_width);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_SECOND,
- (icd->user_height * bytes_per_line));
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_2,
- (0x1 << 8) | /* Enable continuous syncpt */
- TEGRA_VI_SYNCPT_VI);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE_2, 0x00000000);
- } else {
- dev_err(&pcdev->ndev->dev, "Wrong output channel %d\n",
- buf->output_channel);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int tegra_camera_capture_setup(struct tegra_camera_dev *pcdev)
-{
- struct vb2_buffer *vb = pcdev->active;
- struct tegra_buffer *buf = to_tegra_vb(vb);
- struct soc_camera_device *icd = buf->icd;
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int port = pdata->port;
- const struct soc_camera_format_xlate *current_fmt = icd->current_fmt;
- enum v4l2_mbus_pixelcode input_code = current_fmt->code;
- u32 hdr, input_control = 0x0;
-
- switch (input_code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
- input_control |= 0x2 << 8;
- hdr = 30;
- break;
- case V4L2_MBUS_FMT_VYUY8_2X8:
- input_control |= 0x3 << 8;
- hdr = 30;
- break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
- input_control |= 0x0;
- hdr = 30;
- break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
- input_control |= 0x1 << 8;
- hdr = 30;
- break;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- input_control |= 0x2 << 2; /* Input Format = Bayer */
- hdr = 42;
- break;
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- input_control |= 0x2 << 2; /* Input Format = Bayer */
- hdr = 43;
- break;
- default:
- dev_err(&pcdev->ndev->dev, "Input format %d is not supported\n",
- input_code);
- return -EINVAL;
- }
+ BUG_ON(!tegra_camera_port_is_valid(port));
/*
* Set up low pass filter. Use 0x240 for chromaticity and 0x240
@@ -765,25 +653,98 @@ static int tegra_camera_capture_setup(struct tegra_camera_dev *pcdev)
/* Set up raise-on-edge, so we get an interrupt on end of frame. */
TC_VI_REG_WT(pcdev, TEGRA_VI_VI_RAISE, 0x00000001);
- /* Cleanup registers */
- tegra_camera_capture_clean(pcdev);
-
- /* Setup registers for CSI-A, CSI-B and VIP inputs */
if (port == TEGRA_CAMERA_PORT_CSI_A)
- tegra_camera_capture_setup_csi_a(pcdev, icd, hdr);
+ tegra_camera_capture_setup_csi_a(pcdev, input_format,
+ yuv_input_format);
else if (port == TEGRA_CAMERA_PORT_CSI_B)
- tegra_camera_capture_setup_csi_b(pcdev, icd, hdr);
+ tegra_camera_capture_setup_csi_b(pcdev, input_format,
+ yuv_input_format);
else
- tegra_camera_capture_setup_vip(pcdev, icd, input_control);
+ tegra_camera_capture_setup_vip(pcdev, input_format,
+ yuv_input_format);
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
+ (pcdev->pdata->flip_v ? (0x1 << 20) : 0) |
+ (pcdev->pdata->flip_h ? (0x1 << 19) : 0) |
+ (yuv_output_format << 17) |
+ output_format);
+
+ // if the video is interlaced, then take two frames
+ frame_count = IS_INTERLACED ? 2 : 1;
+
+ /*
+ * Set up frame size. Bits 31:16 are the number of lines, and
+ * bits 15:0 are the number of pixels per line.
+ */
+ TC_VI_REG_WT(pcdev, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE,
+ ((icd->user_height/frame_count) << 16) | icd->user_width);
+
+ /* Set the number of frames in the buffer. */
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_FIRST, frame_count);
+
+ /* Set up buffer frame size. */
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_FIRST,
+ ((icd->user_height/frame_count) << 16) | icd->user_width);
+ if(output_fourcc == V4L2_PIX_FMT_YUV420 || output_fourcc == V4L2_PIX_FMT_YVU420) {
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
+ ((icd->user_height/frame_count) * icd->user_width) | (2<<30));
+ }
+ else {
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
+ ((icd->user_height/frame_count) * bytes_per_line) | (2<<30));
+ }
+
+ /* First output memory enabled */
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000);
- /* Setup registers for output channels */
- return tegra_camera_capture_output_channel_setup(pcdev, icd);
}
-static int tegra_camera_capture_buffer_setup(struct tegra_camera_dev *pcdev,
- struct tegra_buffer *buf)
+//
+// make_interlaced
+//
+// make one interlaced frame out of two frames in the buffer @ addr
+// this function must be issued for Y, U and V buffers.
+//
+static void make_interlaced(uint8_t * addr, int width, int height) {
+ uint8_t starting_line_buf[width];
+ bool lines[height];
+ int i;
+ int destination_line, starting_line;
+ for (i = 1; i < height-1; i++) lines[i] = false;
+ lines[0] = true;
+ lines[height-1] = true;
+
+ #define real_line(i) ( (i % 2) ? ((i / 2) + (height/2)) : (i / 2) )
+ while (1) {
+ starting_line = -1;
+ for (i = 1; i < ((height)-1); i++) if (!lines[i]) {
+ starting_line = i;
+ break;
+ }
+ if (starting_line == -1) break; // all is done
+
+ memcpy(starting_line_buf, (void*) ((unsigned int)(addr) + (width*starting_line)), width);
+ destination_line = starting_line;
+ while (1) {
+ lines[destination_line] = true;
+ if (real_line(destination_line) == starting_line) {
+ memcpy(addr + width * destination_line, starting_line_buf, width);
+ break;
+ }
+ memcpy(addr + (width * destination_line), (void*) ((unsigned int)(addr) + (width * real_line(destination_line))), width);
+ destination_line = real_line(destination_line);
+ }
+ }
+}
+
+static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
+ struct tegra_buffer *buf)
{
- struct soc_camera_device *icd = buf->icd;
+ struct soc_camera_device *icd = pcdev->icd;
+ int port = pcdev->pdata->port;
+ int err;
+ int bytes_per_line;
+ uint8_t *src;
switch (icd->current_fmt->host_fmt->fourcc) {
case V4L2_PIX_FMT_YUV420:
@@ -802,90 +763,87 @@ static int tegra_camera_capture_buffer_setup(struct tegra_camera_dev *pcdev,
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
- case V4L2_PIX_FMT_SBGGR8:
- case V4L2_PIX_FMT_SBGGR10:
- /* output 1 */
- if (buf->output_channel == 0) {
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_FIRST,
- buf->buffer_addr);
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_FIRST,
- buf->start_addr);
- /* output 2 */
- } else if (buf->output_channel == 1) {
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_SECOND,
- buf->buffer_addr);
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_SECOND,
- buf->start_addr);
- } else {
- dev_err(&pcdev->ndev->dev, "Wrong output channel %d\n",
- buf->output_channel);
- return -EINVAL;
- }
- break;
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_FIRST,
+ buf->buffer_addr);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_FIRST,
+ buf->start_addr);
+
+ break;
default:
- dev_err(&pcdev->ndev->dev, "Wrong host format %d\n",
- icd->current_fmt->host_fmt->fourcc);
- return -EINVAL;
+ BUG_ON(1);
}
- return 0;
-}
+ BUG_ON(!tegra_camera_port_is_valid(port));
-static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
- struct tegra_buffer *buf)
-{
- struct soc_camera_device *icd = buf->icd;
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int port = pdata->port;
- int err;
+ if (port == TEGRA_CAMERA_PORT_CSI_A)
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
+ 0x0000f005);
+ else if (port == TEGRA_CAMERA_PORT_CSI_B)
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
+ 0x0000f005);
+ else
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
+ 0x00000005); // start & stop
- err = tegra_camera_capture_buffer_setup(pcdev, buf);
- if (err < 0)
- return err;
/*
* Only wait on CSI frame end syncpt if we're using CSI. Otherwise,
* wait on VIP VSYNC syncpt.
*/
- if (port == TEGRA_CAMERA_PORT_CSI_A) {
- pcdev->syncpt_csi_a++;
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
- 0x0000f005);
- err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_A,
- pcdev->syncpt_csi_a,
- TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
- NULL);
- } else if (port == TEGRA_CAMERA_PORT_CSI_B) {
- pcdev->syncpt_csi_b++;
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
- 0x0000f005);
+
+ pcdev->syncpt_vi++;
+ pcdev->syncpt_csi++;
+
+ if (tegra_camera_port_is_csi(port))
err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_B,
- pcdev->syncpt_csi_b,
- TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
- NULL);
- } else {
- pcdev->syncpt_vi++;
- TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
- 0x00000001);
+ TEGRA_VI_SYNCPT_CSI,
+ pcdev->syncpt_csi,
+ TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
+ NULL);
+ else
err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_VI,
- pcdev->syncpt_csi_a,
- TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
- NULL);
- }
+ TEGRA_VI_SYNCPT_VI,
+ pcdev->syncpt_vi,
+ TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
+ NULL);
- if (!err)
- return 0;
+ if (IS_INTERLACED) {
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
+ 0x00000005); // start & stop
+
+ pcdev->syncpt_vi++;
+ pcdev->syncpt_csi++;
+
+ err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
+ TEGRA_VI_SYNCPT_VI,
+ pcdev->syncpt_vi,
+ TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
+ NULL);
+
+ src = (uint8_t*)(buf->virtual_addr);
+ if(icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_YUV420 || icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_YVU420 ) {
+ make_interlaced(src, icd->user_width, icd->user_height); // Y
+ make_interlaced(src + icd->user_width * icd->user_height, icd->user_width, icd->user_height/4); // U
+ make_interlaced(src + icd->user_width * icd->user_height + (icd->user_width * icd->user_height)/4, icd->user_width, icd->user_height/4); // V
+ }
+ else {
+ bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ make_interlaced(src, bytes_per_line, icd->user_height); // Y
+ }
+ }
+
+ if (!err)
+ return 0;
if (tegra_camera_port_is_csi(port)) {
u32 ppstatus;
u32 cilstatus;
u32 rostatus;
- dev_warn(&icd->vdev->dev, "Timeout on CSI syncpt\n");
- dev_warn(&icd->vdev->dev, "buffer_addr = 0x%08x\n",
+ dev_err(&pcdev->ndev->dev, "Timeout on CSI syncpt\n");
+ dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n",
buf->buffer_addr);
ppstatus = TC_VI_REG_RD(pcdev,
@@ -895,7 +853,7 @@ static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
rostatus = TC_VI_REG_RD(pcdev,
TEGRA_CSI_CSI_READONLY_STATUS);
- dev_warn(&icd->vdev->dev,
+ dev_err(&pcdev->ndev->dev,
"PPSTATUS = 0x%08x, "
"CILSTATUS = 0x%08x, "
"ROSTATUS = 0x%08x\n",
@@ -903,14 +861,14 @@ static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
} else {
u32 vip_input_status;
- dev_warn(&pcdev->ndev->dev, "Timeout on VI syncpt\n");
- dev_warn(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n",
+ dev_err(&pcdev->ndev->dev, "Timeout on VI syncpt\n");
+ dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n",
buf->buffer_addr);
vip_input_status = TC_VI_REG_RD(pcdev,
TEGRA_VI_VIP_INPUT_STATUS);
- dev_warn(&pcdev->ndev->dev,
+ dev_err(&pcdev->ndev->dev,
"VIP_INPUT_STATUS = 0x%08x\n",
vip_input_status);
}
@@ -918,10 +876,12 @@ static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
return err;
}
-static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port)
+static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev)
{
+ int port = pcdev->pdata->port;
int err;
- struct tegra_buffer *buf = to_tegra_vb(pcdev->active);
+
+ BUG_ON(!tegra_camera_port_is_valid(port));
if (port == TEGRA_CAMERA_PORT_CSI_A)
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
@@ -929,9 +889,9 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port)
else if (port == TEGRA_CAMERA_PORT_CSI_B)
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
0x0000f002);
- else
- TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
- 0x00000005);
+// else
+// TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
+// 0x00000005);
if (tegra_camera_port_is_csi(port))
err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
@@ -947,28 +907,17 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port)
u32 ppstatus;
u32 cilstatus;
- dev_warn(&pcdev->ndev->dev, "Timeout on VI syncpt\n");
-
- if (buf->output_channel == 0)
- buffer_addr = TC_VI_REG_RD(pcdev,
+ dev_err(&pcdev->ndev->dev, "Timeout on VI syncpt\n");
+ buffer_addr = TC_VI_REG_RD(pcdev,
TEGRA_VI_VB0_BASE_ADDRESS_FIRST);
- else if (buf->output_channel == 1)
- buffer_addr = TC_VI_REG_RD(pcdev,
- TEGRA_VI_VB0_BASE_ADDRESS_SECOND);
- else {
- dev_err(&pcdev->ndev->dev, "Wrong output channel %d\n",
- buf->output_channel);
- return -EINVAL;
- }
-
- dev_warn(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n",
+ dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n",
buffer_addr);
ppstatus = TC_VI_REG_RD(pcdev,
TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
cilstatus = TC_VI_REG_RD(pcdev,
TEGRA_CSI_CSI_CIL_STATUS);
- dev_warn(&pcdev->ndev->dev,
+ dev_err(&pcdev->ndev->dev,
"PPSTATUS = 0x%08x, CILSTATUS = 0x%08x\n",
ppstatus, cilstatus);
}
@@ -976,132 +925,81 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port)
return err;
}
-static void tegra_camera_activate(struct tegra_camera_dev *pcdev)
-{
- nvhost_module_busy_ext(pcdev->ndev);
-
- /* Enable external power */
- regulator_enable(pcdev->reg);
-
- /* Unpowergate VE */
- tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
-
- /* Turn on relevant clocks. */
- clk_set_rate(pcdev->clk_vi, 150000000);
- clk_enable(pcdev->clk_vi);
- clk_set_rate(pcdev->clk_vi_sensor, 24000000);
- clk_enable(pcdev->clk_vi_sensor);
- clk_enable(pcdev->clk_csi);
- clk_enable(pcdev->clk_isp);
- clk_enable(pcdev->clk_csus);
- clk_set_rate(pcdev->clk_sclk, 80000000);
- clk_enable(pcdev->clk_sclk);
- clk_set_rate(pcdev->clk_sclk, 375000000);
- clk_enable(pcdev->clk_emc);
-
- /* Save current syncpt values. */
- tegra_camera_save_syncpts(pcdev);
-}
-
-static void tegra_camera_deactivate(struct tegra_camera_dev *pcdev)
-{
- /* Turn off relevant clocks. */
- clk_disable(pcdev->clk_vi);
- clk_disable(pcdev->clk_vi_sensor);
- clk_disable(pcdev->clk_csi);
- clk_disable(pcdev->clk_isp);
- clk_disable(pcdev->clk_csus);
- clk_disable(pcdev->clk_sclk);
- clk_disable(pcdev->clk_emc);
-
- /* Powergate VE */
- tegra_powergate_partition(TEGRA_POWERGATE_VENC);
-
- /* Disable external power */
- regulator_disable(pcdev->reg);
-
- nvhost_module_idle_ext(pcdev->ndev);
-
- pcdev->cal_done = 0;
-}
-
static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev)
{
- struct vb2_buffer *vb = pcdev->active;
- struct tegra_buffer *buf = to_tegra_vb(vb);
- struct soc_camera_device *icd = buf->icd;
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int port = pdata->port;
+ struct vb2_buffer *vb;
+ struct tegra_buffer *buf;
int retry = TEGRA_SYNCPT_RETRY_COUNT;
- int err;
+ int port = pcdev->pdata->port;
+ int err = 0;
- while (retry) {
- err = tegra_camera_capture_start(pcdev, buf);
- /* Capturing succeed, stop capturing */
- if (!err)
- err = tegra_camera_capture_stop(pcdev, port);
- /* Capturing failed, stop and retry */
- else {
- retry--;
-
- /* Stop streaming. */
- if (port == TEGRA_CAMERA_PORT_CSI_A) {
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
- 0x0000f002);
- /* Clear status registers. */
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_CSI_PIXEL_PARSER_STATUS,
- 0xffffffff);
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_CSI_CIL_STATUS,
- 0xffffffff);
- } else if (port == TEGRA_CAMERA_PORT_CSI_B) {
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
- 0x0000f002);
- /* Clear status registers. */
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_CSI_PIXEL_PARSER_STATUS,
- 0xffffffff);
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_CSI_CIL_STATUS,
- 0xffffffff);
- } else {
- TC_VI_REG_WT(pcdev,
- TEGRA_VI_CAMERA_CONTROL,
- 0x00000005);
- }
+ if (!pcdev->active)
+ return 0;
- tegra_camera_incr_syncpts(pcdev);
- tegra_camera_save_syncpts(pcdev);
+ vb = pcdev->active;
+ buf = to_tegra_vb(vb);
- continue;
+ while (retry--) {
+ err = tegra_camera_capture_start(pcdev, buf);
+ if (err == 0) {
+ err = tegra_camera_capture_stop(pcdev);
+ if (err == 0) break;
}
- break;
- }
+ /* Stop streaming. */
+ if (port == TEGRA_CAMERA_PORT_CSI_A) {
+ TC_VI_REG_WT(pcdev,
+ TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
+ 0x0000f002);
+ /* Clear status registers. */
+ TC_VI_REG_WT(pcdev,
+ TEGRA_CSI_CSI_PIXEL_PARSER_STATUS,
+ 0xffffffff);
+ TC_VI_REG_WT(pcdev,
+ TEGRA_CSI_CSI_CIL_STATUS,
+ 0xffffffff);
+ } else if (port == TEGRA_CAMERA_PORT_CSI_B) {
+ TC_VI_REG_WT(pcdev,
+ TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
+ 0x0000f002);
+ /* Clear status registers. */
+ TC_VI_REG_WT(pcdev,
+ TEGRA_CSI_CSI_PIXEL_PARSER_STATUS,
+ 0xffffffff);
+ TC_VI_REG_WT(pcdev,
+ TEGRA_CSI_CSI_CIL_STATUS,
+ 0xffffffff);
+ } else {
+ TC_VI_REG_WT(pcdev,
+ TEGRA_VI_CAMERA_CONTROL,
+ 0x00000005);
+ }
- /* Reset hardware for too many errors */
- if (!retry) {
- tegra_camera_deactivate(pcdev);
- mdelay(5);
- tegra_camera_activate(pcdev);
- if (pcdev->active)
- tegra_camera_capture_setup(pcdev);
+ tegra_camera_incr_syncpts(pcdev);
+ tegra_camera_save_syncpts(pcdev);
+ continue;
}
spin_lock_irq(&pcdev->videobuf_queue_lock);
+ /*
+ * If vb->state is VB2_BUF_STATE_ERROR, then the vb has already been
+ * removed, so we shouldn't remove it again.
+ */
+ if (vb->state != VB2_BUF_STATE_ERROR)
+ list_del_init(&buf->queue);
+
+ if (!list_empty(&pcdev->capture))
+ pcdev->active = &list_entry(pcdev->capture.next,
+ struct tegra_buffer, queue)->vb;
+ else
+ pcdev->active = NULL;
+
do_gettimeofday(&vb->v4l2_buf.timestamp);
vb->v4l2_buf.field = pcdev->field;
- if (port == TEGRA_CAMERA_PORT_CSI_A)
- vb->v4l2_buf.sequence = pcdev->sequence_a++;
- else if (port == TEGRA_CAMERA_PORT_CSI_B)
- vb->v4l2_buf.sequence = pcdev->sequence_b++;
+ vb->v4l2_buf.sequence = pcdev->sequence++;
- vb2_buffer_done(vb, err < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
- list_del_init(&buf->queue);
+ vb2_buffer_done(vb, (err != 0) ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
pcdev->num_frames++;
@@ -1110,145 +1008,101 @@ static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev)
return err;
}
-static int tegra_camera_csi_pad_calibration(struct tegra_camera_dev *pcdev)
+static void tegra_camera_work(struct work_struct *work)
{
- struct vb2_buffer *vb = pcdev->active;
- struct tegra_buffer *buf = to_tegra_vb(vb);
- struct soc_camera_device *icd = buf->icd;
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int port = pdata->port;
- int retry = 500;
- u32 data;
- int err = -EINVAL;
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DSI_MIPI_CAL_CONFIG, 0x40300);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0, 0x50700);
-
- if (port == TEGRA_CAMERA_PORT_CSI_B || pdata->lanes == 4)
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x200004);
-
- data = 0x2a000004;
- if (port == TEGRA_CAMERA_PORT_CSI_A)
- data |= 0x200000; /* MIPI_CAL_SELA */
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, data);
-
- /* Start calibration */
- data |= 0x80000000;
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, data);
+ struct tegra_camera_dev *pcdev =
+ container_of(work, struct tegra_camera_dev, work);
- while (retry--) {
- data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS);
- if ((data & 0x8000) == 0x8000)
- break;
- udelay(20);
- }
- if (!retry) {
- dev_warn(&pcdev->ndev->dev, "MIPI calibration timeout!\n");
- goto cal_out;
- }
+ mutex_lock(&pcdev->work_mutex);
- /* Clear status */
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, data);
- retry = 500;
- while (retry--) {
- data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS);
- if ((data & 0x8000) == 0x0)
- break;
- udelay(20);
- }
+ while (pcdev->active)
+ tegra_camera_capture_frame(pcdev);
- if (!retry) {
- dev_warn(&pcdev->ndev->dev,
- "Clear MIPI calibration status timeout!\n");
- goto cal_out;
- }
+ mutex_unlock(&pcdev->work_mutex);
+}
- data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
- err = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS);
- if (data | err) {
- dev_warn(&pcdev->ndev->dev,
- "Calibration status not be cleared!\n");
- err = -EINVAL;
- goto cal_out;
- }
+static void tegra_camera_activate(struct tegra_camera_dev *pcdev)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ u32 val;
+ void __iomem *apb_misc;
+#endif
- /* Calibration succeed */
- err = 0;
+ nvhost_module_busy_ext(pcdev->ndev);
-cal_out:
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, data);
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ if(!tegra_powergate_is_powered(TEGRA_POWERGATE_VENC))
+ tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
+#endif
- /* un-select to avoid interference with DSI */
- if (port == TEGRA_CAMERA_PORT_CSI_B || pdata->lanes == 4)
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x4);
+ /* Turn on relevant clocks. */
+ clk_enable(pcdev->clk_vi);
+ clk_enable(pcdev->clk_vi_sensor);
+ clk_enable(pcdev->clk_csi);
+ clk_enable(pcdev->clk_isp);
+ clk_enable(pcdev->clk_csus);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x2a000004);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+ val = readl(apb_misc + 0x42c);
+ writel(val | 0x1, apb_misc + 0x42c);
+#endif
- return err;
+ /* Save current syncpt values. */
+ tegra_camera_save_syncpts(pcdev);
}
-static void tegra_camera_work(struct work_struct *work)
+static void tegra_camera_deactivate(struct tegra_camera_dev *pcdev)
{
- struct tegra_camera_dev *pcdev =
- container_of(work, struct tegra_camera_dev, work);
- struct tegra_buffer *buf;
+ mutex_lock(&pcdev->work_mutex);
- while (1) {
- mutex_lock(&pcdev->work_mutex);
-
- spin_lock_irq(&pcdev->videobuf_queue_lock);
- if (list_empty(&pcdev->capture)) {
- pcdev->active = NULL;
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
- mutex_unlock(&pcdev->work_mutex);
- return;
- }
+ /* Cancel active buffer. */
+ if (pcdev->active) {
+ list_del_init(&to_tegra_vb(pcdev->active)->queue);
+ vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR);
+ pcdev->active = NULL;
+ }
- buf = list_entry(pcdev->capture.next, struct tegra_buffer,
- queue);
- pcdev->active = &buf->vb;
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
+ mutex_unlock(&pcdev->work_mutex);
- tegra_camera_capture_setup(pcdev);
- if (!pcdev->cal_done) {
- tegra_camera_csi_pad_calibration(pcdev);
- pcdev->cal_done = 1;
- }
- tegra_camera_capture_frame(pcdev);
+ /* Turn off relevant clocks. */
+ clk_disable(pcdev->clk_vi);
+ clk_disable(pcdev->clk_vi_sensor);
+ clk_disable(pcdev->clk_csi);
+ clk_disable(pcdev->clk_isp);
+ clk_disable(pcdev->clk_csus);
+
+ nvhost_module_idle_ext(pcdev->ndev);
- mutex_unlock(&pcdev->work_mutex);
- }
}
-static int tegra_camera_init_buffer(struct tegra_buffer *buf)
+static void tegra_camera_init_buffer(struct tegra_camera_dev *pcdev,
+ struct tegra_buffer *buf)
{
- struct soc_camera_device *icd = buf->icd;
+ struct soc_camera_device *icd = pcdev->icd;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
- struct tegra_camera_platform_data *pdata = icd->link->priv;
+ buf->buffer_addr = vb2_dma_nvmap_plane_paddr(&buf->vb, 0); // physical addr
+ buf->virtual_addr = vb2_plane_vaddr(&buf->vb, 0); // save virtual addr for later interlace handling
switch (icd->current_fmt->host_fmt->fourcc) {
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
- case V4L2_PIX_FMT_SBGGR8:
- case V4L2_PIX_FMT_SBGGR10:
- buf->buffer_addr = vb2_dma_nvmap_plane_paddr(&buf->vb, 0);
buf->start_addr = buf->buffer_addr;
- if (pdata->flip_v)
+ if (pcdev->pdata->flip_v)
buf->start_addr += bytes_per_line *
(icd->user_height-1);
- if (pdata->flip_h)
+ if (pcdev->pdata->flip_h)
buf->start_addr += bytes_per_line - 1;
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- buf->buffer_addr = vb2_dma_nvmap_plane_paddr(&buf->vb, 0);
buf->buffer_addr_u = buf->buffer_addr +
icd->user_width * icd->user_height;
buf->buffer_addr_v = buf->buffer_addr_u +
@@ -1265,7 +1119,7 @@ static int tegra_camera_init_buffer(struct tegra_buffer *buf)
buf->start_addr_u = buf->buffer_addr_u;
buf->start_addr_v = buf->buffer_addr_v;
- if (pdata->flip_v) {
+ if (pcdev->pdata->flip_v) {
buf->start_addr += icd->user_width *
(icd->user_height - 1);
@@ -1276,7 +1130,7 @@ static int tegra_camera_init_buffer(struct tegra_buffer *buf)
((icd->user_height/2) - 1));
}
- if (pdata->flip_h) {
+ if (pcdev->pdata->flip_h) {
buf->start_addr += icd->user_width - 1;
buf->start_addr_u += (icd->user_width/2) - 1;
@@ -1287,12 +1141,8 @@ static int tegra_camera_init_buffer(struct tegra_buffer *buf)
break;
default:
- dev_err(icd->parent, "Wrong host format %d\n",
- icd->current_fmt->host_fmt->fourcc);
- return -EINVAL;
+ BUG_ON(1);
}
-
- return 0;
}
/*
@@ -1307,7 +1157,6 @@ static int tegra_camera_videobuf_setup(struct vb2_queue *vq,
struct soc_camera_device *icd = container_of(vq,
struct soc_camera_device,
vb2_vidq);
- struct tegra_camera_platform_data *pdata = icd->link->priv;
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct tegra_camera_dev *pcdev = ici->priv;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
@@ -1320,16 +1169,20 @@ static int tegra_camera_videobuf_setup(struct vb2_queue *vq,
*num_planes = 1;
- if (pdata->port == TEGRA_CAMERA_PORT_CSI_A)
- pcdev->sequence_a = 0;
- else if (pdata->port == TEGRA_CAMERA_PORT_CSI_B)
- pcdev->sequence_b = 0;
+ pcdev->sequence = 0;
sizes[0] = bytes_per_line * icd->user_height;
alloc_ctxs[0] = pcdev->alloc_ctx;
if (!*num_buffers)
*num_buffers = 2;
+ dev_dbg(icd->parent, "num_buffers=%u, size=%lu\n",
+ *num_buffers, sizes[0]);
+
+ tegra_camera_capture_setup(pcdev);
+
+ dev_dbg(icd->parent, "Finished tegra_camera_videobuf_setup()\n");
+
return 0;
}
@@ -1338,8 +1191,9 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb)
struct soc_camera_device *icd = container_of(vb->vb2_queue,
struct soc_camera_device,
vb2_vidq);
- struct tegra_buffer *buf = to_tegra_vb(vb);
- struct tegra_camera_platform_data *pdata = icd->link->priv;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct tegra_camera_dev *pcdev = ici->priv;
+ struct tegra_buffer *buf;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
unsigned long size;
@@ -1349,19 +1203,7 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb)
if (bytes_per_line < 0)
return bytes_per_line;
- buf->icd = icd;
-
- if (!pdata) {
- dev_err(icd->parent, "No platform data for this device!\n");
- return -EINVAL;
- }
-
- if (!tegra_camera_port_is_valid(pdata->port)) {
- dev_err(icd->parent,
- "Invalid camera port %d in platform data\n",
- pdata->port);
- return -EINVAL;
- }
+ buf = to_tegra_vb(vb);
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
vb, vb2_plane_vaddr(vb, 0), vb2_plane_size(vb, 0));
@@ -1375,10 +1217,7 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb)
memset(vb2_plane_vaddr(vb, 0), 0xbd, vb2_plane_size(vb, 0));
#endif
- if (!icd->current_fmt) {
- dev_err(icd->parent, "%s NULL format point\n", __func__);
- return -EINVAL;
- }
+ BUG_ON(NULL == icd->current_fmt);
size = icd->user_height * bytes_per_line;
@@ -1390,7 +1229,11 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb)
vb2_set_plane_payload(vb, 0, size);
- return tegra_camera_init_buffer(buf);
+ tegra_camera_init_buffer(pcdev, buf);
+
+ dev_dbg(icd->parent, "Finished tegra_camera_videobuf_prepare()\n");
+
+ return 0;
}
static void tegra_camera_videobuf_queue(struct vb2_buffer *vb)
@@ -1402,12 +1245,18 @@ static void tegra_camera_videobuf_queue(struct vb2_buffer *vb)
struct tegra_camera_dev *pcdev = ici->priv;
struct tegra_buffer *buf = to_tegra_vb(vb);
+ dev_dbg(icd->parent, "In tegra_camera_videobuf_queue()\n");
+
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
spin_lock_irq(&pcdev->videobuf_queue_lock);
list_add_tail(&buf->queue, &pcdev->capture);
- schedule_work(&pcdev->work);
+
+ if (!pcdev->active) {
+ pcdev->active = vb;
+ schedule_work(&pcdev->work);
+ }
spin_unlock_irq(&pcdev->videobuf_queue_lock);
dev_dbg(icd->parent, "Finished tegra_camera_videobuf_queue()\n");
@@ -1462,24 +1311,16 @@ static int tegra_camera_stop_streaming(struct vb2_queue *q)
struct tegra_camera_dev *pcdev = ici->priv;
struct list_head *buf_head, *tmp;
-
mutex_lock(&pcdev->work_mutex);
spin_lock_irq(&pcdev->videobuf_queue_lock);
- list_for_each_safe(buf_head, tmp, &pcdev->capture) {
- struct tegra_buffer *buf = container_of(buf_head,
- struct tegra_buffer,
- queue);
- if (buf->icd == icd)
- list_del_init(buf_head);
- }
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
- if (pcdev->active) {
- struct tegra_buffer *buf = to_tegra_vb(pcdev->active);
- if (buf->icd == icd)
- pcdev->active = NULL;
- }
+ pcdev->active = NULL;
+
+ list_for_each_safe(buf_head, tmp, &pcdev->capture)
+ list_del_init(buf_head);
+
+ spin_unlock_irq(&pcdev->videobuf_queue_lock);
mutex_unlock(&pcdev->work_mutex);
@@ -1524,13 +1365,24 @@ static int tegra_camera_add_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct tegra_camera_dev *pcdev = ici->priv;
+ int err;
- if (!pcdev->enable_refcnt) {
- pm_runtime_get_sync(ici->v4l2_dev.dev);
- tegra_camera_activate(pcdev);
- pcdev->num_frames = 0;
+ if (pcdev->icd)
+ return -EBUSY;
+
+ pm_runtime_get_sync(ici->v4l2_dev.dev);
+
+ if (pcdev->pdata->enable_camera) {
+ err = pcdev->pdata->enable_camera(pcdev->ndev);
+ if (IS_ERR_VALUE(err))
+ return err;
}
- pcdev->enable_refcnt++;
+
+ tegra_camera_activate(pcdev);
+
+ pcdev->icd = icd;
+
+ pcdev->num_frames = 0;
dev_dbg(icd->parent, "TEGRA Camera host attached to camera %d\n",
icd->devnum);
@@ -1544,12 +1396,14 @@ static void tegra_camera_remove_device(struct soc_camera_device *icd)
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct tegra_camera_dev *pcdev = ici->priv;
- pcdev->enable_refcnt--;
- if (!pcdev->enable_refcnt) {
- cancel_work_sync(&pcdev->work);
- tegra_camera_deactivate(pcdev);
- pm_runtime_put_sync(ici->v4l2_dev.dev);
- }
+ tegra_camera_deactivate(pcdev);
+
+ pcdev->icd = NULL;
+
+ if (pcdev->pdata->disable_camera)
+ pcdev->pdata->disable_camera(pcdev->ndev);
+
+ pm_runtime_put_sync(ici->v4l2_dev.dev);
dev_dbg(icd->parent, "Frames captured: %d\n", pcdev->num_frames);
@@ -1591,8 +1445,6 @@ static int tegra_camera_get_formats(struct soc_camera_device *icd,
case V4L2_MBUS_FMT_VYUY8_2X8:
case V4L2_MBUS_FMT_YUYV8_2X8:
case V4L2_MBUS_FMT_YVYU8_2X8:
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SBGGR10_1X10:
formats += ARRAY_SIZE(tegra_camera_formats);
for (k = 0;
xlate && (k < ARRAY_SIZE(tegra_camera_formats));
@@ -1721,6 +1573,15 @@ static int tegra_camera_try_fmt(struct soc_camera_device *icd,
case V4L2_FIELD_NONE:
pix->field = V4L2_FIELD_NONE;
break;
+ case V4L2_FIELD_INTERLACED_BT:
+ pix->field = V4L2_FIELD_INTERLACED_BT;
+ break;
+ case V4L2_FIELD_INTERLACED_TB:
+ pix->field = V4L2_FIELD_INTERLACED_TB;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ pix->field = V4L2_FIELD_INTERLACED;
+ break;
default:
/* TODO: support interlaced at least in pass-through mode */
dev_err(icd->parent, "Field type %d unsupported.\n",
@@ -1785,7 +1646,8 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
goto exit;
}
- pcdev->ndev = ndev;
+ pcdev->pdata = ndev->dev.platform_data;
+ pcdev->ndev = ndev;
pcdev->ici.priv = pcdev;
pcdev->ici.v4l2_dev.dev = &ndev->dev;
@@ -1798,6 +1660,14 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
spin_lock_init(&pcdev->videobuf_queue_lock);
mutex_init(&pcdev->work_mutex);
+ nvhost_set_drvdata(ndev, pcdev);
+
+ if (!tegra_camera_port_is_valid(pcdev->pdata->port)) {
+ dev_err(&ndev->dev, "Invalid camera port %d in platform data\n",
+ pcdev->pdata->port);
+ goto exit_free_pcdev;
+ }
+
pcdev->clk_vi = clk_get_sys("tegra_camera", "vi");
if (IS_ERR_OR_NULL(pcdev->clk_vi)) {
dev_err(&ndev->dev, "Failed to get vi clock.\n");
@@ -1827,48 +1697,16 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
dev_err(&ndev->dev, "Failed to get csus clock.\n");
goto exit_put_clk_isp;
}
-
- pcdev->clk_sclk = clk_get_sys("tegra_camera", "sclk");
- if (IS_ERR_OR_NULL(pcdev->clk_sclk)) {
- dev_err(&ndev->dev, "Failed to get sclk clock.\n");
- goto exit_put_clk_csus;
- }
-
- pcdev->clk_emc = clk_get_sys("tegra_camera", "emc");
- if (IS_ERR_OR_NULL(pcdev->clk_emc)) {
- dev_err(&ndev->dev, "Failed to get emc clock.\n");
- goto exit_put_clk_sclk;
- }
-
clk_set_rate(pcdev->clk_vi, 150000000);
clk_set_rate(pcdev->clk_vi_sensor, 24000000);
- /* Get regulator pointer */
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- pcdev->reg = regulator_get(&ndev->dev, "vcsi");
-#else
- pcdev->reg = regulator_get(&ndev->dev, "avdd_dsi_csi");
-#endif
- if (IS_ERR_OR_NULL(pcdev->reg)) {
- dev_err(&ndev->dev, "%s: couldn't get regulator\n",
- __func__);
- goto exit_put_clk_emc;
- }
-
- nvhost_set_drvdata(ndev, pcdev);
err = nvhost_client_device_get_resources(ndev);
- if (err) {
- dev_err(&ndev->dev, "%s: nvhost get resources failed %d\n",
- __func__, err);
- goto exit_put_regulator;
- }
+ if (err)
+ goto exit_put_clk_csus;
- err = nvhost_client_device_init(ndev);
- if (err) {
- dev_err(&ndev->dev, "%s: nvhost init failed %d\n",
- __func__, err);
- goto exit_put_regulator;
- }
+ // initialize nvhost client device only the first time
+ if (ndev->power_attrib == NULL)
+ nvhost_client_device_init(ndev);
pcdev->vi_base = ndev->aperture;
@@ -1876,10 +1714,10 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
pm_runtime_enable(&ndev->dev);
pm_runtime_resume(&ndev->dev);
- pcdev->alloc_ctx = vb2_dma_nvmap_init_ctx(&ndev->dev);
+ pcdev->alloc_ctx = vb2_dma_nvmap_init_ctx(pcdev->ici.v4l2_dev.dev);
if (IS_ERR(pcdev->alloc_ctx)) {
err = PTR_ERR(pcdev->alloc_ctx);
- goto exit_pm_disable;
+ goto exit_put_resources;
}
err = soc_camera_host_register(&pcdev->ici);
@@ -1892,15 +1730,9 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
exit_cleanup_alloc_ctx:
vb2_dma_nvmap_cleanup_ctx(pcdev->alloc_ctx);
-exit_pm_disable:
+exit_put_resources:
pm_runtime_disable(&ndev->dev);
nvhost_client_device_put_resources(ndev);
-exit_put_regulator:
- regulator_put(pcdev->reg);
-exit_put_clk_emc:
- clk_put(pcdev->clk_emc);
-exit_put_clk_sclk:
- clk_put(pcdev->clk_sclk);
exit_put_clk_csus:
clk_put(pcdev->clk_csus);
exit_put_clk_isp:
@@ -1963,6 +1795,11 @@ static int tegra_camera_suspend(struct nvhost_device *ndev, pm_message_t state)
/* Suspend the camera sensor. */
WARN_ON(!pcdev->icd->ops->suspend);
pcdev->icd->ops->suspend(pcdev->icd, state);
+
+ /* Power off the camera subsystem. */
+ pcdev->pdata->disable_camera(pcdev->ndev);
+
+ nvhost_module_idle_ext(nvhost_get_parent(ndev));
}
return 0;
@@ -1976,10 +1813,14 @@ static int tegra_camera_resume(struct nvhost_device *ndev)
/* We only need to do something if a camera sensor is attached. */
if (pcdev->icd) {
+ nvhost_module_busy_ext(nvhost_get_parent(ndev));
+
+ /* Power on the camera subsystem. */
+ pcdev->pdata->enable_camera(pcdev->ndev);
+
/* Resume the camera host. */
tegra_camera_save_syncpts(pcdev);
- if (pcdev->active)
- tegra_camera_capture_setup(pcdev);
+ tegra_camera_capture_setup(pcdev);
/* Resume the camera sensor. */
WARN_ON(!pcdev->icd->ops->resume);
@@ -2021,6 +1862,5 @@ module_exit(tegra_camera_exit);
MODULE_DESCRIPTION("TEGRA SoC Camera Host driver");
MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
-MODULE_AUTHOR("Bryan Wu <pengw@nvidia.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("nvhost:" TEGRA_CAM_DRV_NAME);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 10dba0cbda97..1f131d797583 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -297,6 +297,7 @@ config MFD_STMPE
GPIO: stmpe-gpio
Keypad: stmpe-keypad
Touchscreen: stmpe-ts
+ ADC: stmpe-adc
config MFD_TC3589X
bool "Support Toshiba TC35892 and variants"
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index 2963689cf45c..0c556fa65dd2 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -350,6 +350,25 @@ static struct mfd_cell stmpe_ts_cell = {
};
/*
+ * ADC (STMPE811)
+ */
+
+static struct resource stmpe_adc_resources[] = {
+ {
+ .name = "STMPE_ADC",
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell stmpe_adc_cell = {
+ .name = "stmpe-adc",
+ .resources = stmpe_adc_resources,
+ .num_resources = ARRAY_SIZE(stmpe_adc_resources),
+};
+
+/*
* STMPE811
*/
@@ -381,6 +400,11 @@ static struct stmpe_variant_block stmpe811_blocks[] = {
.irq = STMPE811_IRQ_TOUCH_DET,
.block = STMPE_BLOCK_TOUCHSCREEN,
},
+ {
+ .cell = &stmpe_adc_cell,
+ .irq = STMPE811_IRQ_ADC,
+ .block = STMPE_BLOCK_ADC,
+ },
};
static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks,
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index 9a146c8bba92..1c140e5ace4f 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -96,6 +96,7 @@ struct tps6586x {
struct mutex lock;
struct device *dev;
struct i2c_client *client;
+ enum tps6586x_type type;
struct gpio_chip gpio;
struct irq_chip irq_chip;
@@ -255,6 +256,14 @@ out:
}
EXPORT_SYMBOL_GPL(tps6586x_update);
+enum tps6586x_type tps6586x_gettype(struct device *dev)
+{
+ struct tps6586x *tps6586x = dev_get_drvdata(dev);
+
+ return tps6586x->type;
+}
+EXPORT_SYMBOL_GPL(tps6586x_gettype);
+
static struct i2c_client *tps6586x_i2c_client = NULL;
static void tps6586x_power_off(void)
{
@@ -517,17 +526,36 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
return -ENOTSUPP;
}
+ tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
+ if (tps6586x == NULL)
+ return -ENOMEM;
+
ret = i2c_smbus_read_byte_data(client, TPS6586X_VERSIONCRC);
if (ret < 0) {
dev_err(&client->dev, "Chip ID read failed: %d\n", ret);
- return -EIO;
+ ret = -EIO;
+ goto err_irq_init;
+ }
+ tps6586x->type = (enum tps6586x_type)ret;
+ switch (ret) {
+ case TPS658621A:
+ dev_info(&client->dev, "found TPS658621A, ");
+ break;
+ case TPS658621D:
+ dev_info(&client->dev, "found TPS658621D, ");
+ break;
+ case TPS658623:
+ dev_info(&client->dev, "found TPS658623, ");
+ break;
+ case TPS658643:
+ dev_info(&client->dev, "found TPS658643, ");
+ break;
+ default:
+ dev_info(&client->dev, "unknown TPS6586X found, ");
+ tps6586x->type = TPS6586X_ANY;
}
- dev_info(&client->dev, "VERSIONCRC is %02x\n", ret);
-
- tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
- if (tps6586x == NULL)
- return -ENOMEM;
+ printk("VERSIONCRC is %02x\n", ret);
tps6586x->client = client;
tps6586x->dev = &client->dev;
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 8ff35e4cbfe4..73b65ce3089e 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -942,7 +942,13 @@ static struct sdhci_pltfm_data sdhci_tegra_pdata = {
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_NO_CALC_MAX_DISCARD_TO |
- SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+ SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+#if defined(CONFIG_MACH_APALIS_T30) || defined(CONFIG_MACH_COLIBRI_T30)
+/* Hack: SDR12, SDR25, SDR50, SDR104 and DDR50 all require 1.8V signalling which
+ our current T30 designs can't do. */
+ SDHCI_QUIRK2_NO_1_8_V |
+#endif
+ 0,
.ops = &tegra_sdhci_ops,
};
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3a440dcf0f24..da1547ffc9da 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -486,7 +486,10 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
if (offset) {
if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, &flags);
+/* Hack to avoid extensive warning messages from Redpine Signals LiteFi driver */
+#ifndef CONFIG_MACH_COLIBRI_T20
WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
+#endif
memcpy(align, buffer, offset);
sdhci_kunmap_atomic(buffer, &flags);
}
@@ -2658,9 +2661,13 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_card_is_removable(mmc) && !(host->ops->get_cd))
mmc->caps |= MMC_CAP_NEEDS_POLL;
- /* UHS-I mode(s) supported by the host controller. */
- if (host->version >= SDHCI_SPEC_300)
- mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
+ if (host->quirks & SDHCI_QUIRK2_NO_1_8_V)
+ caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
+ SDHCI_SUPPORT_DDR50);
+ else
+ /* UHS-I mode(s) supported by the host controller. */
+ if (host->version >= SDHCI_SPEC_300)
+ mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
/* SDR104 supports also implies SDR50 support */
if (caps[1] & SDHCI_SUPPORT_SDR104)
diff --git a/drivers/mtd/devices/tegra_nand.c b/drivers/mtd/devices/tegra_nand.c
index 38baa40746c6..6034f0b2f239 100644
--- a/drivers/mtd/devices/tegra_nand.c
+++ b/drivers/mtd/devices/tegra_nand.c
@@ -434,6 +434,35 @@ static int nand_cmd_get_status(struct tegra_nand_info *info, uint32_t *status)
return 0;
}
+static int tegra_nand_cmd_reset(struct tegra_nand_info *info,
+ uint32_t *chip_id)
+{
+ int err;
+ uint32_t status = 0;
+
+#ifdef TEGRA_NAND_DEBUG_PEDANTIC
+ BUG_ON(info->chip.curr_chip == -1);
+#endif
+
+ info->command_reg = (COMMAND_CLE |
+ (COMMAND_CE(info->chip.curr_chip)));
+ writel(NAND_CMD_RESET, CMD_REG1);
+ writel(0, CMD_REG2);
+ writel(0, ADDR_REG1);
+ writel(0, ADDR_REG2);
+ writel(0, CONFIG_REG);
+
+ err = tegra_nand_go(info);
+ if (err != 0)
+ return err;
+
+ err = nand_cmd_get_status(info, &status);
+ if (err != 0)
+ return err;
+
+ return 0;
+}
+
/* must be called with lock held */
static int check_block_isbad(struct mtd_info *mtd, loff_t offs)
{
@@ -1400,6 +1429,11 @@ static int tegra_nand_scan(struct mtd_info *mtd, int maxchips)
writel(0, CONFIG_REG);
select_chip(info, 0);
+
+ err = tegra_nand_cmd_reset(info, &tmp);
+ if (err != 0)
+ goto out_error;
+
err = tegra_nand_cmd_readid(info, &tmp);
if (err != 0)
goto out_error;
@@ -1458,7 +1492,7 @@ static int tegra_nand_scan(struct mtd_info *mtd, int maxchips)
/* page_size */
tmp = dev_parms & 0x3;
- mtd->writesize = 1024 << tmp;
+ mtd->writesize = mtd->writebufsize = 1024 << tmp;
info->chip.column_mask = mtd->writesize - 1;
if (mtd->writesize > 4096) {
@@ -1481,6 +1515,11 @@ static int tegra_nand_scan(struct mtd_info *mtd, int maxchips)
/* data block size (erase size) (w/o spare) */
tmp = (dev_parms >> 4) & 0x3;
+ /* work around wrong block size identified for our device
+ Note: ONFI would really be the way to go but has not been supported
+ in Linux prior to version 2.6.37. */
+ if ((vendor_id == 0x2C) && (dev_id == 0x38))
+ tmp += 1;
mtd->erasesize = (64 * 1024) << tmp;
info->chip.block_shift = ffs(mtd->erasesize) - 1;
/* bus width of the nand chip 8/16 */
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 00cf1b0d6053..a56bf52acf5e 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -104,6 +104,7 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
/* 8 Gigabit */
+ {"NAND 1GiB 1,8V 8-bit", 0x38, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index 330140ee266d..535e4032da2b 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -593,6 +593,18 @@ static int mcp251x_do_set_bittiming(struct net_device *net)
return 0;
}
+static int mcp251x_get_berr_counter(const struct net_device *dev, struct can_berr_counter *bec)
+{
+ struct mcp251x_priv *priv = netdev_priv(dev);
+ struct spi_device *spi = priv->spi;
+ uint8_t tec,rec;
+
+ mcp251x_read_2regs(spi, TEC, &tec, &rec);
+ bec->txerr = tec;
+ bec->rxerr = rec;
+ return 0;
+}
+
static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
struct spi_device *spi)
{
@@ -997,6 +1009,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
priv = netdev_priv(net);
priv->can.bittiming_const = &mcp251x_bittiming_const;
priv->can.do_set_mode = mcp251x_do_set_mode;
+ priv->can.do_get_berr_counter = mcp251x_get_berr_counter;
priv->can.clock.freq = pdata->oscillator_frequency / 2;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c
index d9fadc489b32..c8428f25d914 100644
--- a/drivers/net/can/sja1000/sja1000_platform.c
+++ b/drivers/net/can/sja1000/sja1000_platform.c
@@ -38,12 +38,24 @@ MODULE_LICENSE("GPL v2");
static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg)
{
+#if !defined(CONFIG_MACH_COLIBRI_T20) && !defined(CONFIG_MACH_COLIBRI_T30)
return ioread8(priv->reg_base + reg);
+#else
+ u8 value;
+ iowrite8(reg, priv->reg_base);
+ value = ioread8(priv->reg_base + 8);
+ return value;
+#endif
}
static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val)
{
+#if !defined(CONFIG_MACH_COLIBRI_T20) && !defined(CONFIG_MACH_COLIBRI_T30)
iowrite8(val, priv->reg_base + reg);
+#else
+ iowrite8(reg, priv->reg_base);
+ iowrite8(val, priv->reg_base + 8);
+#endif
}
static u8 sp_read_reg16(const struct sja1000_priv *priv, int reg)
diff --git a/drivers/net/igb/Makefile b/drivers/net/igb/Makefile
index c6e4621b6262..01193b8460fc 100644
--- a/drivers/net/igb/Makefile
+++ b/drivers/net/igb/Makefile
@@ -33,5 +33,6 @@
obj-$(CONFIG_IGB) += igb.o
igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
- e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o
+ e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \
+ e1000_i210.o
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index c0857bdfb03a..ad3bf1792d7c 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -34,6 +34,7 @@
#include "e1000_mac.h"
#include "e1000_82575.h"
+#include "e1000_i210.h"
static s32 igb_get_invariants_82575(struct e1000_hw *);
static s32 igb_acquire_phy_82575(struct e1000_hw *);
@@ -50,6 +51,8 @@ static s32 igb_write_phy_reg_82580(struct e1000_hw *, u32, u16);
static s32 igb_reset_hw_82575(struct e1000_hw *);
static s32 igb_reset_hw_82580(struct e1000_hw *);
static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *, bool);
+static s32 igb_set_d0_lplu_state_82580(struct e1000_hw *, bool);
+static s32 igb_set_d3_lplu_state_82580(struct e1000_hw *, bool);
static s32 igb_setup_copper_link_82575(struct e1000_hw *);
static s32 igb_setup_serdes_link_82575(struct e1000_hw *);
static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16);
@@ -98,6 +101,8 @@ static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw)
break;
case e1000_82580:
case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
reg = rd32(E1000_MDICNFG);
ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO);
break;
@@ -152,6 +157,17 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
case E1000_DEV_ID_I350_SGMII:
mac->type = e1000_i350;
break;
+ case E1000_DEV_ID_I210_COPPER:
+ case E1000_DEV_ID_I210_COPPER_OEM1:
+ case E1000_DEV_ID_I210_COPPER_IT:
+ case E1000_DEV_ID_I210_FIBER:
+ case E1000_DEV_ID_I210_SERDES:
+ case E1000_DEV_ID_I210_SGMII:
+ mac->type = e1000_i210;
+ break;
+ case E1000_DEV_ID_I211_COPPER:
+ mac->type = e1000_i211;
+ break;
default:
return -E1000_ERR_MAC_INIT;
break;
@@ -184,26 +200,44 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
/* Set mta register count */
mac->mta_reg_count = 128;
/* Set rar entry count */
- mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
- if (mac->type == e1000_82576)
+ switch (mac->type) {
+ case e1000_82576:
mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
- if (mac->type == e1000_82580)
+ break;
+ case e1000_82580:
mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
- if (mac->type == e1000_i350)
+ break;
+ case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
+ break;
+ default:
+ mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
+ break;
+ }
/* reset */
if (mac->type >= e1000_82580)
mac->ops.reset_hw = igb_reset_hw_82580;
else
mac->ops.reset_hw = igb_reset_hw_82575;
+
+ if (mac->type >= e1000_i210) {
+ mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_i210;
+ mac->ops.release_swfw_sync = igb_release_swfw_sync_i210;
+ } else {
+ mac->ops.acquire_swfw_sync = igb_acquire_swfw_sync_82575;
+ mac->ops.release_swfw_sync = igb_release_swfw_sync_82575;
+ }
+
/* Set if part includes ASF firmware */
mac->asf_firmware_present = true;
/* Set if manageability features are enabled. */
mac->arc_subsystem_valid =
(rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK)
? true : false;
- /* enable EEE on i350 parts */
- if (mac->type == e1000_i350)
+ /* enable EEE on i350 parts and later parts */
+ if (mac->type >= e1000_i350)
dev_spec->eee_disable = false;
else
dev_spec->eee_disable = true;
@@ -215,26 +249,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
/* NVM initialization */
eecd = rd32(E1000_EECD);
-
- nvm->opcode_bits = 8;
- nvm->delay_usec = 1;
- switch (nvm->override) {
- case e1000_nvm_override_spi_large:
- nvm->page_size = 32;
- nvm->address_bits = 16;
- break;
- case e1000_nvm_override_spi_small:
- nvm->page_size = 8;
- nvm->address_bits = 8;
- break;
- default:
- nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
- nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
- break;
- }
-
- nvm->type = e1000_nvm_eeprom_spi;
-
size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
E1000_EECD_SIZE_EX_SHIFT);
@@ -244,6 +258,33 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
*/
size += NVM_WORD_SIZE_BASE_SHIFT;
+ nvm->word_size = 1 << size;
+ if (hw->mac.type < e1000_i210) {
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd
+ & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd
+ & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+ if (nvm->word_size == (1 << 15))
+ nvm->page_size = 128;
+
+ nvm->type = e1000_nvm_eeprom_spi;
+ } else
+ nvm->type = e1000_nvm_flash_hw;
+
/*
* Check for invalid size
*/
@@ -252,32 +293,60 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
"defaulting to 32K.\n");
size = 15;
}
- nvm->word_size = 1 << size;
- if (nvm->word_size == (1 << 15))
- nvm->page_size = 128;
/* NVM Function Pointers */
- nvm->ops.acquire = igb_acquire_nvm_82575;
- if (nvm->word_size < (1 << 15))
- nvm->ops.read = igb_read_nvm_eerd;
- else
- nvm->ops.read = igb_read_nvm_spi;
-
- nvm->ops.release = igb_release_nvm_82575;
switch (hw->mac.type) {
case e1000_82580:
nvm->ops.validate = igb_validate_nvm_checksum_82580;
nvm->ops.update = igb_update_nvm_checksum_82580;
+ nvm->ops.acquire = igb_acquire_nvm_82575;
+ nvm->ops.release = igb_release_nvm_82575;
+ if (nvm->word_size < (1 << 15))
+ nvm->ops.read = igb_read_nvm_eerd;
+ else
+ nvm->ops.read = igb_read_nvm_spi;
+ nvm->ops.write = igb_write_nvm_spi;
break;
case e1000_i350:
nvm->ops.validate = igb_validate_nvm_checksum_i350;
nvm->ops.update = igb_update_nvm_checksum_i350;
+ nvm->ops.acquire = igb_acquire_nvm_82575;
+ nvm->ops.release = igb_release_nvm_82575;
+ if (nvm->word_size < (1 << 15))
+ nvm->ops.read = igb_read_nvm_eerd;
+ else
+ nvm->ops.read = igb_read_nvm_spi;
+ nvm->ops.write = igb_write_nvm_spi;
+ break;
+ case e1000_i210:
+ nvm->ops.validate = igb_validate_nvm_checksum_i210;
+ nvm->ops.update = igb_update_nvm_checksum_i210;
+ nvm->ops.acquire = igb_acquire_nvm_i210;
+ nvm->ops.release = igb_release_nvm_i210;
+ nvm->ops.read = igb_read_nvm_srrd_i210;
+ nvm->ops.valid_led_default = igb_valid_led_default_i210;
+ break;
+ case e1000_i211:
+ nvm->ops.acquire = igb_acquire_nvm_i210;
+ nvm->ops.release = igb_release_nvm_i210;
+ nvm->ops.read = igb_read_nvm_i211;
+ nvm->ops.valid_led_default = igb_valid_led_default_i210;
+ nvm->ops.validate = NULL;
+ nvm->ops.update = NULL;
+ nvm->ops.write = NULL;
break;
default:
nvm->ops.validate = igb_validate_nvm_checksum;
nvm->ops.update = igb_update_nvm_checksum;
+ nvm->ops.acquire = igb_acquire_nvm_82575;
+ nvm->ops.release = igb_release_nvm_82575;
+ if (nvm->word_size < (1 << 15))
+ nvm->ops.read = igb_read_nvm_eerd;
+ else
+ nvm->ops.read = igb_read_nvm_spi;
+ nvm->ops.write = igb_write_nvm_spi;
+ break;
}
- nvm->ops.write = igb_write_nvm_spi;
/* if part supports SR-IOV then initialize mailbox parameters */
switch (mac->type) {
@@ -315,9 +384,13 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
if (igb_sgmii_active_82575(hw) && !igb_sgmii_uses_mdio_82575(hw)) {
phy->ops.read_reg = igb_read_phy_reg_sgmii_82575;
phy->ops.write_reg = igb_write_phy_reg_sgmii_82575;
- } else if (hw->mac.type >= e1000_82580) {
+ } else if ((hw->mac.type == e1000_82580)
+ || (hw->mac.type == e1000_i350)) {
phy->ops.read_reg = igb_read_phy_reg_82580;
phy->ops.write_reg = igb_write_phy_reg_82580;
+ } else if (hw->phy.type >= e1000_phy_i210) {
+ phy->ops.read_reg = igb_read_phy_reg_gs40g;
+ phy->ops.write_reg = igb_write_phy_reg_gs40g;
} else {
phy->ops.read_reg = igb_read_phy_reg_igp;
phy->ops.write_reg = igb_write_phy_reg_igp;
@@ -346,6 +419,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
else
phy->ops.get_cable_length = igb_get_cable_length_m88;
+ if (phy->id == I210_I_PHY_ID) {
+ phy->ops.get_cable_length =
+ igb_get_cable_length_m88_gen2;
+ phy->ops.set_d0_lplu_state =
+ igb_set_d0_lplu_state_82580;
+ phy->ops.set_d3_lplu_state =
+ igb_set_d3_lplu_state_82580;
+ }
phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
break;
case IGP03E1000_E_PHY_ID:
@@ -362,6 +443,17 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_82580;
phy->ops.get_cable_length = igb_get_cable_length_82580;
phy->ops.get_phy_info = igb_get_phy_info_82580;
+ phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
+ phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
+ break;
+ case I210_I_PHY_ID:
+ phy->type = e1000_phy_i210;
+ phy->ops.get_phy_info = igb_get_phy_info_m88;
+ phy->ops.check_polarity = igb_check_polarity_m88;
+ phy->ops.get_cable_length = igb_get_cable_length_m88_gen2;
+ phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82580;
+ phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
+ phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
break;
default:
return -E1000_ERR_PHY;
@@ -388,7 +480,7 @@ static s32 igb_acquire_phy_82575(struct e1000_hw *hw)
else if (hw->bus.func == E1000_FUNC_3)
mask = E1000_SWFW_PHY3_SM;
- return igb_acquire_swfw_sync_82575(hw, mask);
+ return hw->mac.ops.acquire_swfw_sync(hw, mask);
}
/**
@@ -409,7 +501,7 @@ static void igb_release_phy_82575(struct e1000_hw *hw)
else if (hw->bus.func == E1000_FUNC_3)
mask = E1000_SWFW_PHY3_SM;
- igb_release_swfw_sync_82575(hw, mask);
+ hw->mac.ops.release_swfw_sync(hw, mask);
}
/**
@@ -513,6 +605,8 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
break;
case e1000_82580:
case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
mdic = rd32(E1000_MDICNFG);
mdic &= E1000_MDICNFG_PHY_MASK;
phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT;
@@ -677,6 +771,96 @@ out:
}
/**
+ * igb_set_d0_lplu_state_82580 - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: true to enable LPLU, false to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+static s32 igb_set_d0_lplu_state_82580(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val = 0;
+ u16 data;
+
+ data = rd32(E1000_82580_PHY_POWER_MGMT);
+
+ if (active) {
+ data |= E1000_82580_PM_D0_LPLU;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ data &= ~E1000_82580_PM_SPD;
+ } else {
+ data &= ~E1000_82580_PM_D0_LPLU;
+
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on)
+ data |= E1000_82580_PM_SPD;
+ else if (phy->smart_speed == e1000_smart_speed_off)
+ data &= ~E1000_82580_PM_SPD; }
+
+ wr32(E1000_82580_PHY_POWER_MGMT, data);
+ return ret_val;
+}
+
+/**
+ * igb_set_d3_lplu_state_82580 - Sets low power link up state for D3
+ * @hw: pointer to the HW structure
+ * @active: boolean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D3
+ * and SmartSpeed is disabled when active is true, else clear lplu for D3
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained.
+ **/
+s32 igb_set_d3_lplu_state_82580(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val = 0;
+ u16 data;
+
+ data = rd32(E1000_82580_PHY_POWER_MGMT);
+
+ if (!active) {
+ data &= ~E1000_82580_PM_D3_LPLU;
+ /*
+ * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained.
+ */
+ if (phy->smart_speed == e1000_smart_speed_on)
+ data |= E1000_82580_PM_SPD;
+ else if (phy->smart_speed == e1000_smart_speed_off)
+ data &= ~E1000_82580_PM_SPD;
+ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+ data |= E1000_82580_PM_D3_LPLU;
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ data &= ~E1000_82580_PM_SPD;
+ }
+
+ wr32(E1000_82580_PHY_POWER_MGMT, data);
+ return ret_val;
+}
+
+/**
* igb_acquire_nvm_82575 - Request for access to EEPROM
* @hw: pointer to the HW structure
*
@@ -689,14 +873,14 @@ static s32 igb_acquire_nvm_82575(struct e1000_hw *hw)
{
s32 ret_val;
- ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+ ret_val = hw->mac.ops.acquire_swfw_sync(hw, E1000_SWFW_EEP_SM);
if (ret_val)
goto out;
ret_val = igb_acquire_nvm(hw);
if (ret_val)
- igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+ hw->mac.ops.release_swfw_sync(hw, E1000_SWFW_EEP_SM);
out:
return ret_val;
@@ -712,7 +896,7 @@ out:
static void igb_release_nvm_82575(struct e1000_hw *hw)
{
igb_release_nvm(hw);
- igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+ hw->mac.ops.release_swfw_sync(hw, E1000_SWFW_EEP_SM);
}
/**
@@ -1080,7 +1264,6 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
* is no link.
*/
igb_clear_hw_cntrs_82575(hw);
-
return ret_val;
}
@@ -1117,6 +1300,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
}
}
switch (hw->phy.type) {
+ case e1000_phy_i210:
case e1000_phy_m88:
if (hw->phy.id == I347AT4_E_PHY_ID ||
hw->phy.id == M88E1112_E_PHY_ID)
@@ -1740,7 +1924,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw)
/* Determine whether or not a global dev reset is requested */
if (global_device_reset &&
- igb_acquire_swfw_sync_82575(hw, swmbsw_mask))
+ hw->mac.ops.acquire_swfw_sync(hw, swmbsw_mask))
global_device_reset = false;
if (global_device_reset &&
@@ -1786,7 +1970,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw)
/* Release semaphore */
if (global_device_reset)
- igb_release_swfw_sync_82575(hw, swmbsw_mask);
+ hw->mac.ops.release_swfw_sync(hw, swmbsw_mask);
return ret_val;
}
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
index 786e110011a3..b477b20a2b05 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/igb/e1000_82575.h
@@ -55,10 +55,11 @@ extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
#define E1000_SRRCTL_DROP_EN 0x80000000
#define E1000_SRRCTL_TIMESTAMP 0x40000000
+
#define E1000_MRQC_ENABLE_RSS_4Q 0x00000002
#define E1000_MRQC_ENABLE_VMDQ 0x00000003
-#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005
#define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
+#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005
#define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index 7b8ddd830f19..e32e3a71eff1 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -452,6 +452,7 @@
#define E1000_ERR_INVALID_ARGUMENT 16
#define E1000_ERR_NO_SPACE 17
#define E1000_ERR_NVM_PBA_SECTION 18
+#define E1000_ERR_INVM_VALUE_NOT_FOUND 19
/* Loop limit on how long we wait for auto-negotiation to complete */
#define COPPER_LINK_UP_LIMIT 10
@@ -589,6 +590,25 @@
#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
#define E1000_EECD_SIZE_EX_SHIFT 11
+#define E1000_EECD_FLUPD_I210 0x00800000 /* Update FLASH */
+#define E1000_EECD_FLUDONE_I210 0x04000000 /* Update FLASH done*/
+#define E1000_FLUDONE_ATTEMPTS 20000
+#define E1000_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */
+#define E1000_I210_FIFO_SEL_RX 0x00
+#define E1000_I210_FIFO_SEL_TX_QAV(_i) (0x02 + (_i))
+#define E1000_I210_FIFO_SEL_TX_LEGACY E1000_I210_FIFO_SEL_TX_QAV(0)
+#define E1000_I210_FIFO_SEL_BMC2OS_TX 0x06
+#define E1000_I210_FIFO_SEL_BMC2OS_RX 0x01
+#define E1000_EECD_FLUPD_I210 0x00800000 /* Update FLASH */
+#define E1000_EECD_FLUDONE_I210 0x04000000 /* Update FLASH done*/
+#define E1000_FLUDONE_ATTEMPTS 20000
+#define E1000_EERD_EEWR_MAX_COUNT 512 /* buffered EEPROM words rw */
+#define E1000_I210_FIFO_SEL_RX 0x00
+#define E1000_I210_FIFO_SEL_TX_QAV(_i) (0x02 + (_i))
+#define E1000_I210_FIFO_SEL_TX_LEGACY E1000_I210_FIFO_SEL_TX_QAV(0)
+#define E1000_I210_FIFO_SEL_BMC2OS_TX 0x06
+#define E1000_I210_FIFO_SEL_BMC2OS_RX 0x01
+
/* Offset to data in NVM read/write registers */
#define E1000_NVM_RW_REG_DATA 16
@@ -607,6 +627,16 @@
#define NVM_CHECKSUM_REG 0x003F
#define NVM_COMPATIBILITY_REG_3 0x0003
#define NVM_COMPATIBILITY_BIT_MASK 0x8000
+#define NVM_MAC_ADDR 0x0000
+#define NVM_SUB_DEV_ID 0x000B
+#define NVM_SUB_VEN_ID 0x000C
+#define NVM_DEV_ID 0x000D
+#define NVM_VEN_ID 0x000E
+#define NVM_INIT_CTRL_2 0x000F
+#define NVM_INIT_CTRL_4 0x0013
+#define NVM_LED_1_CFG 0x001C
+#define NVM_LED_0_2_CFG 0x001F
+
#define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */
#define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */
@@ -633,6 +663,7 @@
#define NVM_PBA_OFFSET_0 8
#define NVM_PBA_OFFSET_1 9
+#define NVM_RESERVED_WORD 0xFFFF
#define NVM_PBA_PTR_GUARD 0xFAFA
#define NVM_WORD_SIZE_BASE_SHIFT 6
@@ -690,6 +721,7 @@
#define I82580_I_PHY_ID 0x015403A0
#define I350_I_PHY_ID 0x015403B0
#define M88_VENDOR 0x0141
+#define I210_I_PHY_ID 0x01410C00
/* M88E1000 Specific Registers */
#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
@@ -809,6 +841,7 @@
#define E1000_IPCNFG_EEE_100M_AN 0x00000004 /* EEE Enable 100M AN */
#define E1000_EEER_TX_LPI_EN 0x00010000 /* EEE Tx LPI Enable */
#define E1000_EEER_RX_LPI_EN 0x00020000 /* EEE Rx LPI Enable */
+#define E1000_EEER_FRC_AN 0x10000000 /* Enable EEE in loopback */
#define E1000_EEER_LPI_FC 0x00040000 /* EEE Enable on FC */
/* SerDes Control */
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index 4519a1367170..6542df695834 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -63,6 +63,23 @@ struct e1000_hw;
#define E1000_DEV_ID_I350_FIBER 0x1522
#define E1000_DEV_ID_I350_SERDES 0x1523
#define E1000_DEV_ID_I350_SGMII 0x1524
+#ifdef CONFIG_MACH_APALIS_T30
+/* Hack: Springville with a blank Flash (tools only, not for driver) */
+#define E1000_DEV_ID_I210_COPPER 0x1531
+#else
+#define E1000_DEV_ID_I210_COPPER 0x1533
+#endif
+#define E1000_DEV_ID_I210_COPPER_OEM1 0x1534
+#define E1000_DEV_ID_I210_COPPER_IT 0x1535
+#define E1000_DEV_ID_I210_FIBER 0x1536
+#define E1000_DEV_ID_I210_SERDES 0x1537
+#define E1000_DEV_ID_I210_SGMII 0x1538
+#ifdef CONFIG_MACH_APALIS_T30
+/* Hack: I211 with a blank iNVM (tools only, not for driver) */
+#define E1000_DEV_ID_I211_COPPER 0x1532
+#else
+#define E1000_DEV_ID_I211_COPPER 0x1539
+#endif
#define E1000_REVISION_2 2
#define E1000_REVISION_4 4
@@ -83,6 +100,8 @@ enum e1000_mac_type {
e1000_82576,
e1000_82580,
e1000_i350,
+ e1000_i210,
+ e1000_i211,
e1000_num_macs /* List is 1-based, so subtract 1 for true count. */
};
@@ -117,6 +136,7 @@ enum e1000_phy_type {
e1000_phy_igp_3,
e1000_phy_ife,
e1000_phy_82580,
+ e1000_phy_i210,
};
enum e1000_bus_type {
@@ -313,6 +333,9 @@ struct e1000_mac_operations {
void (*rar_set)(struct e1000_hw *, u8 *, u32);
s32 (*read_mac_addr)(struct e1000_hw *);
s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
+ s32 (*acquire_swfw_sync)(struct e1000_hw *, u16);
+ void (*release_swfw_sync)(struct e1000_hw *, u16);
+
};
struct e1000_phy_operations {
@@ -338,6 +361,7 @@ struct e1000_nvm_operations {
s32 (*write)(struct e1000_hw *, u16, u16, u16 *);
s32 (*update)(struct e1000_hw *);
s32 (*validate)(struct e1000_hw *);
+ s32 (*valid_led_default)(struct e1000_hw *, u16 *);
};
struct e1000_info {
diff --git a/drivers/net/igb/e1000_i210.c b/drivers/net/igb/e1000_i210.c
new file mode 100644
index 000000000000..77a5f939bc74
--- /dev/null
+++ b/drivers/net/igb/e1000_i210.c
@@ -0,0 +1,603 @@
+/*******************************************************************************
+
+ Intel(R) Gigabit Ethernet Linux driver
+ Copyright(c) 2007-2012 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+******************************************************************************/
+
+/* e1000_i210
+ * e1000_i211
+ */
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+
+#include "e1000_hw.h"
+#include "e1000_i210.h"
+
+static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw);
+static void igb_put_hw_semaphore_i210(struct e1000_hw *hw);
+static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data);
+static s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw);
+
+/**
+ * igb_acquire_nvm_i210 - Request for access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the necessary semaphores for exclusive access to the EEPROM.
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 igb_acquire_nvm_i210(struct e1000_hw *hw)
+{
+ return igb_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ * igb_release_nvm_i210 - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit,
+ * then release the semaphores acquired.
+ **/
+void igb_release_nvm_i210(struct e1000_hw *hw)
+{
+ igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ * igb_acquire_swfw_sync_i210 - Acquire SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
+ * will also specify which port we're acquiring the lock for.
+ **/
+s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+ u32 swmask = mask;
+ u32 fwmask = mask << 16;
+ s32 ret_val = E1000_SUCCESS;
+ s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
+
+ while (i < timeout) {
+ if (igb_get_hw_semaphore_i210(hw)) {
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync = rd32(E1000_SW_FW_SYNC);
+ if (!(swfw_sync & fwmask))
+ break;
+
+ /*
+ * Firmware currently using resource (fwmask)
+ */
+ igb_put_hw_semaphore_i210(hw);
+ mdelay(5);
+ i++;
+ }
+
+ if (i == timeout) {
+ hw_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ goto out;
+ }
+
+ swfw_sync |= swmask;
+ wr32(E1000_SW_FW_SYNC, swfw_sync);
+
+ igb_put_hw_semaphore_i210(hw);
+out:
+ return ret_val;
+}
+
+/**
+ * igb_release_swfw_sync_i210 - Release SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Release the SW/FW semaphore used to access the PHY or NVM. The mask
+ * will also specify which port we're releasing the lock for.
+ **/
+void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+
+ while (igb_get_hw_semaphore_i210(hw) != E1000_SUCCESS)
+ ; /* Empty */
+
+ swfw_sync = rd32(E1000_SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ wr32(E1000_SW_FW_SYNC, swfw_sync);
+
+ igb_put_hw_semaphore_i210(hw);
+}
+
+/**
+ * igb_get_hw_semaphore_i210 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw)
+{
+ u32 swsm;
+ s32 ret_val = E1000_SUCCESS;
+ s32 timeout = hw->nvm.word_size + 1;
+ s32 i = 0;
+
+ /* Get the FW semaphore. */
+ for (i = 0; i < timeout; i++) {
+ swsm = rd32(E1000_SWSM);
+ wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ }
+
+ if (i == timeout) {
+ /* Release semaphores */
+ igb_put_hw_semaphore(hw);
+ hw_dbg("Driver can't access the NVM\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * igb_put_hw_semaphore_i210 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+static void igb_put_hw_semaphore_i210(struct e1000_hw *hw)
+{
+ u32 swsm;
+
+ swsm = rd32(E1000_SWSM);
+
+ swsm &= ~E1000_SWSM_SWESMBI;
+
+ wr32(E1000_SWSM, swsm);
+}
+
+/**
+ * igb_read_nvm_srrd_i210 - Reads Shadow Ram using EERD register
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the Shadow Ram to read
+ * @words: number of words to read
+ * @data: word read from the Shadow Ram
+ *
+ * Reads a 16 bit word from the Shadow Ram using the EERD register.
+ * Uses necessary synchronization semaphores.
+ **/
+s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 status = E1000_SUCCESS;
+ u16 i, count;
+
+ /* We cannot hold synchronization semaphores for too long,
+ * because of forceful takeover procedure. However it is more efficient
+ * to read in bursts than synchronizing access for each word. */
+ for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
+ count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
+ E1000_EERD_EEWR_MAX_COUNT : (words - i);
+ if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
+ status = igb_read_nvm_eerd(hw, offset, count,
+ data + i);
+ hw->nvm.ops.release(hw);
+ } else {
+ status = E1000_ERR_SWFW_SYNC;
+ }
+
+ if (status != E1000_SUCCESS)
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * igb_write_nvm_srwr_i210 - Write to Shadow RAM using EEWR
+ * @hw: pointer to the HW structure
+ * @offset: offset within the Shadow RAM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the Shadow RAM
+ *
+ * Writes data to Shadow RAM at offset using EEWR register.
+ *
+ * If e1000_update_nvm_checksum is not called after this function , the
+ * data will not be committed to FLASH and also Shadow RAM will most likely
+ * contain an invalid checksum.
+ *
+ * If error code is returned, data and Shadow RAM may be inconsistent - buffer
+ * partially written.
+ **/
+s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 status = E1000_SUCCESS;
+ u16 i, count;
+
+ /* We cannot hold synchronization semaphores for too long,
+ * because of forceful takeover procedure. However it is more efficient
+ * to write in bursts than synchronizing access for each word. */
+ for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
+ count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
+ E1000_EERD_EEWR_MAX_COUNT : (words - i);
+ if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
+ status = igb_write_nvm_srwr(hw, offset, count,
+ data + i);
+ hw->nvm.ops.release(hw);
+ } else {
+ status = E1000_ERR_SWFW_SYNC;
+ }
+
+ if (status != E1000_SUCCESS)
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * igb_write_nvm_srwr - Write to Shadow Ram using EEWR
+ * @hw: pointer to the HW structure
+ * @offset: offset within the Shadow Ram to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the Shadow Ram
+ *
+ * Writes data to Shadow Ram at offset using EEWR register.
+ *
+ * If igb_update_nvm_checksum is not called after this function , the
+ * Shadow Ram will most likely contain an invalid checksum.
+ **/
+static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 i, k, eewr = 0;
+ u32 attempts = 100000;
+ s32 ret_val = E1000_SUCCESS;
+
+ /*
+ * A check for invalid values: offset too large, too many words,
+ * too many words for the offset, and not enough words.
+ */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ hw_dbg("nvm parameter(s) out of bounds\n");
+ ret_val = -E1000_ERR_NVM;
+ goto out;
+ }
+
+ for (i = 0; i < words; i++) {
+ eewr = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
+ (data[i] << E1000_NVM_RW_REG_DATA) |
+ E1000_NVM_RW_REG_START;
+
+ wr32(E1000_SRWR, eewr);
+
+ for (k = 0; k < attempts; k++) {
+ if (E1000_NVM_RW_REG_DONE &
+ rd32(E1000_SRWR)) {
+ ret_val = E1000_SUCCESS;
+ break;
+ }
+ udelay(5);
+ }
+
+ if (ret_val != E1000_SUCCESS) {
+ hw_dbg("Shadow RAM write EEWR timed out\n");
+ break;
+ }
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * igb_read_nvm_i211 - Read NVM wrapper function for I211
+ * @hw: pointer to the HW structure
+ * @address: the word address (aka eeprom offset) to read
+ * @data: pointer to the data read
+ *
+ * Wrapper function to return data formerly found in the NVM.
+ **/
+s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ /* Only the MAC addr is required to be present in the iNVM */
+ switch (offset) {
+ case NVM_MAC_ADDR:
+ ret_val = igb_read_invm_i211(hw, offset, &data[0]);
+ ret_val |= igb_read_invm_i211(hw, offset+1, &data[1]);
+ ret_val |= igb_read_invm_i211(hw, offset+2, &data[2]);
+ if (ret_val != E1000_SUCCESS)
+ hw_dbg("MAC Addr not found in iNVM\n");
+ break;
+ case NVM_ID_LED_SETTINGS:
+ case NVM_INIT_CTRL_2:
+ case NVM_INIT_CTRL_4:
+ case NVM_LED_1_CFG:
+ case NVM_LED_0_2_CFG:
+ igb_read_invm_i211(hw, offset, data);
+ break;
+ case NVM_COMPAT:
+ *data = ID_LED_DEFAULT_I210;
+ break;
+ case NVM_SUB_DEV_ID:
+ *data = hw->subsystem_device_id;
+ break;
+ case NVM_SUB_VEN_ID:
+ *data = hw->subsystem_vendor_id;
+ break;
+ case NVM_DEV_ID:
+ *data = hw->device_id;
+ break;
+ case NVM_VEN_ID:
+ *data = hw->vendor_id;
+ break;
+ default:
+ hw_dbg("NVM word 0x%02x is not mapped.\n", offset);
+ *data = NVM_RESERVED_WORD;
+ break;
+ }
+ return ret_val;
+}
+
+/**
+ * igb_read_invm_i211 - Reads OTP
+ * @hw: pointer to the HW structure
+ * @address: the word address (aka eeprom offset) to read
+ * @data: pointer to the data read
+ *
+ * Reads 16-bit words from the OTP. Return error when the word is not
+ * stored in OTP.
+ **/
+s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data)
+{
+ s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND;
+ u32 invm_dword;
+ u16 i;
+ u8 record_type, word_address;
+
+ for (i = 0; i < E1000_INVM_SIZE; i++) {
+ invm_dword = rd32(E1000_INVM_DATA_REG(i));
+ /* Get record type */
+ record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword);
+ if (record_type == E1000_INVM_UNINITIALIZED_STRUCTURE)
+ break;
+ if (record_type == E1000_INVM_CSR_AUTOLOAD_STRUCTURE)
+ i += E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS;
+ if (record_type == E1000_INVM_RSA_KEY_SHA256_STRUCTURE)
+ i += E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS;
+ if (record_type == E1000_INVM_WORD_AUTOLOAD_STRUCTURE) {
+ word_address = INVM_DWORD_TO_WORD_ADDRESS(invm_dword);
+ if (word_address == (u8)address) {
+ *data = INVM_DWORD_TO_WORD_DATA(invm_dword);
+ hw_dbg("Read INVM Word 0x%02x = %x",
+ address, *data);
+ status = E1000_SUCCESS;
+ break;
+ }
+ }
+ }
+ if (status != E1000_SUCCESS)
+ hw_dbg("Requested word 0x%02x not found in OTP\n", address);
+ return status;
+}
+
+/**
+ * igb_validate_nvm_checksum_i210 - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
+{
+ s32 status = E1000_SUCCESS;
+ s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *);
+
+ if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
+
+ /*
+ * Replace the read function with semaphore grabbing with
+ * the one that skips this for a while.
+ * We have semaphore taken already here.
+ */
+ read_op_ptr = hw->nvm.ops.read;
+ hw->nvm.ops.read = igb_read_nvm_eerd;
+
+ status = igb_validate_nvm_checksum(hw);
+
+ /* Revert original read operation. */
+ hw->nvm.ops.read = read_op_ptr;
+
+ hw->nvm.ops.release(hw);
+ } else {
+ status = E1000_ERR_SWFW_SYNC;
+ }
+
+ return status;
+}
+
+
+/**
+ * igb_update_nvm_checksum_i210 - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM. Next commit EEPROM data onto the Flash.
+ **/
+s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u16 checksum = 0;
+ u16 i, nvm_data;
+
+ /*
+ * Read the first word from the EEPROM. If this times out or fails, do
+ * not continue or we could be in for a very long wait while every
+ * EEPROM read fails
+ */
+ ret_val = igb_read_nvm_eerd(hw, 0, 1, &nvm_data);
+ if (ret_val != E1000_SUCCESS) {
+ hw_dbg("EEPROM read failed\n");
+ goto out;
+ }
+
+ if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
+ /*
+ * Do not use hw->nvm.ops.write, hw->nvm.ops.read
+ * because we do not want to take the synchronization
+ * semaphores twice here.
+ */
+
+ for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+ ret_val = igb_read_nvm_eerd(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ hw->nvm.ops.release(hw);
+ hw_dbg("NVM Read Error while updating checksum.\n");
+ goto out;
+ }
+ checksum += nvm_data;
+ }
+ checksum = (u16) NVM_SUM - checksum;
+ ret_val = igb_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
+ &checksum);
+ if (ret_val != E1000_SUCCESS) {
+ hw->nvm.ops.release(hw);
+ hw_dbg("NVM Write Error while updating checksum.\n");
+ goto out;
+ }
+
+ hw->nvm.ops.release(hw);
+
+ ret_val = igb_update_flash_i210(hw);
+ } else {
+ ret_val = -E1000_ERR_SWFW_SYNC;
+ }
+out:
+ return ret_val;
+}
+
+/**
+ * igb_update_flash_i210 - Commit EEPROM to the flash
+ * @hw: pointer to the HW structure
+ *
+ **/
+s32 igb_update_flash_i210(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_SUCCESS;
+ u32 flup;
+
+ ret_val = igb_pool_flash_update_done_i210(hw);
+ if (ret_val == -E1000_ERR_NVM) {
+ hw_dbg("Flash update time out\n");
+ goto out;
+ }
+
+ flup = rd32(E1000_EECD) | E1000_EECD_FLUPD_I210;
+ wr32(E1000_EECD, flup);
+
+ ret_val = igb_pool_flash_update_done_i210(hw);
+ if (ret_val == E1000_SUCCESS)
+ hw_dbg("Flash update complete\n");
+ else
+ hw_dbg("Flash update time out\n");
+
+out:
+ return ret_val;
+}
+
+/**
+ * igb_pool_flash_update_done_i210 - Pool FLUDONE status.
+ * @hw: pointer to the HW structure
+ *
+ **/
+s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw)
+{
+ s32 ret_val = -E1000_ERR_NVM;
+ u32 i, reg;
+
+ for (i = 0; i < E1000_FLUDONE_ATTEMPTS; i++) {
+ reg = rd32(E1000_EECD);
+ if (reg & E1000_EECD_FLUDONE_I210) {
+ ret_val = E1000_SUCCESS;
+ break;
+ }
+ udelay(5);
+ }
+
+ return ret_val;
+}
+
+/**
+ * igb_valid_led_default_i210 - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ hw_dbg("NVM Read Error\n");
+ goto out;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
+ switch (hw->phy.media_type) {
+ case e1000_media_type_internal_serdes:
+ *data = ID_LED_DEFAULT_I210_SERDES;
+ break;
+ case e1000_media_type_copper:
+ default:
+ *data = ID_LED_DEFAULT_I210;
+ break;
+ }
+ }
+out:
+ return ret_val;
+}
diff --git a/drivers/net/igb/e1000_i210.h b/drivers/net/igb/e1000_i210.h
new file mode 100644
index 000000000000..5dc2bd3f50bc
--- /dev/null
+++ b/drivers/net/igb/e1000_i210.h
@@ -0,0 +1,76 @@
+/*******************************************************************************
+
+ Intel(R) Gigabit Ethernet Linux driver
+ Copyright(c) 2007-2012 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_I210_H_
+#define _E1000_I210_H_
+
+extern s32 igb_update_flash_i210(struct e1000_hw *hw);
+extern s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw);
+extern s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw);
+extern s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data);
+extern s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data);
+extern s32 igb_read_invm_i211(struct e1000_hw *hw, u16 address, u16 *data);
+extern s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
+extern void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
+extern s32 igb_acquire_nvm_i210(struct e1000_hw *hw);
+extern void igb_release_nvm_i210(struct e1000_hw *hw);
+extern s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data);
+extern s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data);
+
+#define E1000_STM_OPCODE 0xDB00
+#define E1000_EEPROM_FLASH_SIZE_WORD 0x11
+
+#define INVM_DWORD_TO_RECORD_TYPE(invm_dword) \
+ (u8)((invm_dword) & 0x7)
+#define INVM_DWORD_TO_WORD_ADDRESS(invm_dword) \
+ (u8)(((invm_dword) & 0x0000FE00) >> 9)
+#define INVM_DWORD_TO_WORD_DATA(invm_dword) \
+ (u16)(((invm_dword) & 0xFFFF0000) >> 16)
+
+enum E1000_INVM_STRUCTURE_TYPE {
+ E1000_INVM_UNINITIALIZED_STRUCTURE = 0x00,
+ E1000_INVM_WORD_AUTOLOAD_STRUCTURE = 0x01,
+ E1000_INVM_CSR_AUTOLOAD_STRUCTURE = 0x02,
+ E1000_INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE = 0x03,
+ E1000_INVM_RSA_KEY_SHA256_STRUCTURE = 0x04,
+ E1000_INVM_INVALIDATED_STRUCTURE = 0x0F,
+};
+
+#define E1000_INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS 8
+#define E1000_INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS 1
+
+#define ID_LED_DEFAULT_I210 ((ID_LED_OFF1_ON2 << 8) | \
+ (ID_LED_OFF1_OFF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+#define ID_LED_DEFAULT_I210_SERDES ((ID_LED_DEF1_DEF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#endif
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c
index 2b5ef761d2ab..c3ee7b21ab4e 100644
--- a/drivers/net/igb/e1000_mac.c
+++ b/drivers/net/igb/e1000_mac.c
@@ -596,6 +596,7 @@ s32 igb_setup_link(struct e1000_hw *hw)
ret_val = igb_set_fc_watermarks(hw);
out:
+
return ret_val;
}
diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/igb/e1000_nvm.c
index 40407124e722..38047a584605 100644
--- a/drivers/net/igb/e1000_nvm.c
+++ b/drivers/net/igb/e1000_nvm.c
@@ -710,4 +710,3 @@ s32 igb_update_nvm_checksum(struct e1000_hw *hw)
out:
return ret_val;
}
-
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index e662554c62d6..d9e0ec065cf7 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/igb/e1000_phy.c
@@ -35,6 +35,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw);
static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
u16 *phy_ctrl);
static s32 igb_wait_autoneg(struct e1000_hw *hw);
+static s32 igb_set_master_slave_mode(struct e1000_hw *hw);
/* Cable length tables */
static const u16 e1000_m88_cable_length_table[] =
@@ -564,6 +565,11 @@ s32 igb_copper_link_setup_m88(struct e1000_hw *hw)
hw_dbg("Error committing the PHY changes\n");
goto out;
}
+ if (phy->type == e1000_phy_i210) {
+ ret_val = igb_set_master_slave_mode(hw);
+ if (ret_val)
+ return ret_val;
+ }
out:
return ret_val;
@@ -1207,12 +1213,22 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
goto out;
if (!link) {
- if (hw->phy.type != e1000_phy_m88 ||
- hw->phy.id == I347AT4_E_PHY_ID ||
- hw->phy.id == M88E1112_E_PHY_ID) {
+ bool reset_dsp = true;
+
+ switch (hw->phy.id) {
+ case I347AT4_E_PHY_ID:
+ case M88E1112_E_PHY_ID:
+ case I210_I_PHY_ID:
+ reset_dsp = false;
+ break;
+ default:
+ if (hw->phy.type != e1000_phy_m88)
+ reset_dsp = false;
+ break;
+ }
+ if (!reset_dsp)
hw_dbg("Link taking longer than expected.\n");
- } else {
-
+ else {
/*
* We didn't get link.
* Reset the DSP and cross our fingers.
@@ -1237,7 +1253,8 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
if (hw->phy.type != e1000_phy_m88 ||
hw->phy.id == I347AT4_E_PHY_ID ||
- hw->phy.id == M88E1112_E_PHY_ID)
+ hw->phy.id == M88E1112_E_PHY_ID ||
+ hw->phy.id == I210_I_PHY_ID)
goto out;
ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
@@ -1435,6 +1452,7 @@ s32 igb_check_downshift(struct e1000_hw *hw)
u16 phy_data, offset, mask;
switch (phy->type) {
+ case e1000_phy_i210:
case e1000_phy_m88:
case e1000_phy_gg82563:
offset = M88E1000_PHY_SPEC_STATUS;
@@ -1470,7 +1488,7 @@ out:
*
* Polarity is determined based on the PHY specific status register.
**/
-static s32 igb_check_polarity_m88(struct e1000_hw *hw)
+s32 igb_check_polarity_m88(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val;
@@ -1659,6 +1677,7 @@ s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw)
u16 phy_data, phy_data2, index, default_page, is_cm;
switch (hw->phy.id) {
+ case I210_I_PHY_ID:
case I347AT4_E_PHY_ID:
/* Remember the original page select and set it to 7 */
ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
@@ -2123,10 +2142,16 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw)
void igb_power_up_phy_copper(struct e1000_hw *hw)
{
u16 mii_reg = 0;
+ u16 power_reg = 0;
/* The PHY will retain its settings across a power down/up cycle */
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
mii_reg &= ~MII_CR_POWER_DOWN;
+ if (hw->phy.type == e1000_phy_i210) {
+ hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg);
+ power_reg &= ~GS40G_CS_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg);
+ }
hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
}
@@ -2140,10 +2165,18 @@ void igb_power_up_phy_copper(struct e1000_hw *hw)
void igb_power_down_phy_copper(struct e1000_hw *hw)
{
u16 mii_reg = 0;
+ u16 power_reg = 0;
/* The PHY will retain its settings across a power down/up cycle */
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
mii_reg |= MII_CR_POWER_DOWN;
+
+ /* i210 Phy requires an additional bit for power up/down */
+ if (hw->phy.type == e1000_phy_i210) {
+ hw->phy.ops.read_reg(hw, GS40G_COPPER_SPEC, &power_reg);
+ power_reg |= GS40G_CS_POWER_DOWN;
+ hw->phy.ops.write_reg(hw, GS40G_COPPER_SPEC, power_reg);
+ }
hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
msleep(1);
}
@@ -2339,3 +2372,103 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw)
out:
return ret_val;
}
+
+/**
+ * igb_write_phy_reg_gs40g - Write GS40G PHY register
+ * @hw: pointer to the HW structure
+ * @offset: lower half is register offset to write to
+ * upper half is page to use.
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ s32 ret_val;
+ u16 page = offset >> GS40G_PAGE_SHIFT;
+
+ offset = offset & GS40G_OFFSET_MASK;
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page);
+ if (ret_val)
+ goto release;
+ ret_val = igb_write_phy_reg_mdic(hw, offset, data);
+
+release:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+/**
+ * igb_read_phy_reg_gs40g - Read GS40G PHY register
+ * @hw: pointer to the HW structure
+ * @offset: lower half is register offset to read to
+ * upper half is page to use.
+ * @data: data to read at register offset
+ *
+ * Acquires semaphore, if necessary, then reads the data in the PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ s32 ret_val;
+ u16 page = offset >> GS40G_PAGE_SHIFT;
+
+ offset = offset & GS40G_OFFSET_MASK;
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page);
+ if (ret_val)
+ goto release;
+ ret_val = igb_read_phy_reg_mdic(hw, offset, data);
+
+release:
+ hw->phy.ops.release(hw);
+ return ret_val;
+}
+
+/**
+ * igb_set_master_slave_mode - Setup PHY for Master/slave mode
+ * @hw: pointer to the HW structure
+ *
+ * Sets up Master/slave mode
+ **/
+static s32 igb_set_master_slave_mode(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 phy_data;
+
+ /* Resolve Master/Slave mode */
+ ret_val = hw->phy.ops.read_reg(hw, PHY_1000T_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* load defaults for future use */
+ hw->phy.original_ms_type = (phy_data & CR_1000T_MS_ENABLE) ?
+ ((phy_data & CR_1000T_MS_VALUE) ?
+ e1000_ms_force_master :
+ e1000_ms_force_slave) : e1000_ms_auto;
+
+ switch (hw->phy.ms_type) {
+ case e1000_ms_force_master:
+ phy_data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_force_slave:
+ phy_data |= CR_1000T_MS_ENABLE;
+ phy_data &= ~(CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_auto:
+ phy_data &= ~CR_1000T_MS_ENABLE;
+ /* fall-through */
+ default:
+ break;
+ }
+
+ return hw->phy.ops.write_reg(hw, PHY_1000T_CTRL, phy_data);
+}
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h
index 8510797b9d81..3b813a8bdf1a 100644
--- a/drivers/net/igb/e1000_phy.h
+++ b/drivers/net/igb/e1000_phy.h
@@ -73,6 +73,9 @@ s32 igb_copper_link_setup_82580(struct e1000_hw *hw);
s32 igb_get_phy_info_82580(struct e1000_hw *hw);
s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw);
s32 igb_get_cable_length_82580(struct e1000_hw *hw);
+s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
+s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data);
+s32 igb_check_polarity_m88(struct e1000_hw *hw);
/* IGP01E1000 Specific Registers */
#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
@@ -114,6 +117,13 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw);
/* I82580 PHY Diagnostics Status */
#define I82580_DSTATUS_CABLE_LENGTH 0x03FC
#define I82580_DSTATUS_CABLE_LENGTH_SHIFT 2
+
+/* 82580 PHY Power Management */
+#define E1000_82580_PHY_POWER_MGMT 0xE14
+#define E1000_82580_PM_SPD 0x0001 /* Smart Power Down */
+#define E1000_82580_PM_D0_LPLU 0x0002 /* For D0a states */
+#define E1000_82580_PM_D3_LPLU 0x0004 /* For all other states */
+
/* Enable flexible speed on link-up */
#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */
#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */
@@ -133,4 +143,16 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw);
#define E1000_CABLE_LENGTH_UNDEFINED 0xFF
+/* GS40G - I210 PHY defines */
+#define GS40G_PAGE_SELECT 0x16
+#define GS40G_PAGE_SHIFT 16
+#define GS40G_OFFSET_MASK 0xFFFF
+#define GS40G_PAGE_2 0x20000
+#define GS40G_MAC_REG2 0x15
+#define GS40G_MAC_LB 0x4140
+#define GS40G_MAC_SPEED_1G 0X0006
+#define GS40G_COPPER_SPEC 0x0010
+#define GS40G_CS_POWER_DOWN 0x0002
+#define GS40G_LINE_LB 0x4000
+
#endif
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index 0990f6d860c7..bb62cf641318 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -351,4 +351,18 @@
#define E1000_O2BGPTC 0x08FE4 /* OS2BMC packets received by BMC */
#define E1000_O2BSPC 0x0415C /* OS2BMC packets transmitted by host */
+#define E1000_SRWR 0x12018 /* Shadow Ram Write Register - RW */
+#define E1000_I210_FLMNGCTL 0x12038
+#define E1000_I210_FLMNGDATA 0x1203C
+#define E1000_I210_FLMNGCNT 0x12040
+
+#define E1000_I210_FLSWCTL 0x12048
+#define E1000_I210_FLSWDATA 0x1204C
+#define E1000_I210_FLSWCNT 0x12050
+
+#define E1000_I210_FLA 0x1201C
+
+#define E1000_INVM_DATA_REG(_n) (0x12120 + 4*(_n))
+#define E1000_INVM_SIZE 64 /* Number of INVM Data Registers */
+
#endif
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index 265e151b66c4..111236008d16 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -61,11 +61,14 @@ struct igb_adapter;
#define MAX_Q_VECTORS 8
/* Transmit and receive queues */
-#define IGB_MAX_RX_QUEUES (adapter->vfs_allocated_count ? 2 : \
- (hw->mac.type > e1000_82575 ? 8 : 4))
+#define IGB_MAX_RX_QUEUES ((adapter->vfs_allocated_count ? 2 : \
+ (hw->mac.type > e1000_82575 ? 8 : 4)))
+#define IGB_MAX_RX_QUEUES_I210 4
+#define IGB_MAX_RX_QUEUES_I211 2
#define IGB_ABS_MAX_TX_QUEUES 8
-#define IGB_MAX_TX_QUEUES IGB_MAX_RX_QUEUES
-
+#define IGB_MAX_TX_QUEUES 16
+#define IGB_MAX_TX_QUEUES_I210 4
+#define IGB_MAX_TX_QUEUES_I211 2
#define IGB_MAX_VF_MC_ENTRIES 30
#define IGB_MAX_VF_FUNCTIONS 8
#define IGB_MAX_VFTA_ENTRIES 128
@@ -227,8 +230,9 @@ struct igb_ring {
};
};
-#define IGB_RING_FLAG_RX_CSUM 0x00000001 /* RX CSUM enabled */
-#define IGB_RING_FLAG_RX_SCTP_CSUM 0x00000002 /* SCTP CSUM offload enabled */
+#define IGB_RING_FLAG_RX_CSUM 0x00000001 /* RX CSUM enabled */
+#define IGB_RING_FLAG_RX_SCTP_CSUM 0x00000002 /* SCTP CSUM offload enabled */
+#define IGB_RING_FLAG_RX_LB_VLAN_BSWAP 0x00000003
#define IGB_RING_FLAG_TX_CTX_IDX 0x00000001 /* HW requires context index */
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index 414b0225be89..c9e3d65bd71d 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -549,10 +549,13 @@ static void igb_get_regs(struct net_device *netdev,
regs_buff[548] = rd32(E1000_TDFT);
regs_buff[549] = rd32(E1000_TDFHS);
regs_buff[550] = rd32(E1000_TDFPC);
- regs_buff[551] = adapter->stats.o2bgptc;
- regs_buff[552] = adapter->stats.b2ospc;
- regs_buff[553] = adapter->stats.o2bspc;
- regs_buff[554] = adapter->stats.b2ogprc;
+
+ if (hw->mac.type > e1000_82580) {
+ regs_buff[551] = adapter->stats.o2bgptc;
+ regs_buff[552] = adapter->stats.b2ospc;
+ regs_buff[553] = adapter->stats.o2bspc;
+ regs_buff[554] = adapter->stats.b2ogprc;
+ }
}
static int igb_get_eeprom_len(struct net_device *netdev)
@@ -621,6 +624,9 @@ static int igb_set_eeprom(struct net_device *netdev,
if (eeprom->len == 0)
return -EOPNOTSUPP;
+ if (hw->mac.type == e1000_i211)
+ return -EOPNOTSUPP;
+
if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
return -EFAULT;
@@ -855,6 +861,36 @@ struct igb_reg_test {
#define TABLE64_TEST_LO 5
#define TABLE64_TEST_HI 6
+/* i210 reg test */
+static struct igb_reg_test reg_test_i210[] = {
+ { E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+ { E1000_FCAH, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
+ { E1000_FCT, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
+ { E1000_RDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+ { E1000_RDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+ { E1000_RDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+ /* RDH is read-only for i210, only test RDT. */
+ { E1000_RDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+ { E1000_FCRTH, 0x100, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
+ { E1000_FCTTV, 0x100, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+ { E1000_TIPG, 0x100, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
+ { E1000_TDBAL(0), 0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+ { E1000_TDBAH(0), 0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+ { E1000_TDLEN(0), 0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+ { E1000_TDT(0), 0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+ { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
+ { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
+ { E1000_RCTL, 0x100, 1, SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
+ { E1000_TCTL, 0x100, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
+ { E1000_RA, 0, 16, TABLE64_TEST_LO,
+ 0xFFFFFFFF, 0xFFFFFFFF },
+ { E1000_RA, 0, 16, TABLE64_TEST_HI,
+ 0x900FFFFF, 0xFFFFFFFF },
+ { E1000_MTA, 0, 128, TABLE32_TEST,
+ 0xFFFFFFFF, 0xFFFFFFFF },
+ { 0, 0, 0, 0, 0 }
+};
+
/* i350 reg test */
static struct igb_reg_test reg_test_i350[] = {
{ E1000_FCAL, 0x100, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
@@ -1077,6 +1113,11 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data)
test = reg_test_i350;
toggle = 0x7FEFF3FF;
break;
+ case e1000_i210:
+ case e1000_i211:
+ test = reg_test_i210;
+ toggle = 0x7FEFF3FF;
+ break;
case e1000_82580:
test = reg_test_82580;
toggle = 0x7FEFF3FF;
@@ -1158,23 +1199,13 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data)
static int igb_eeprom_test(struct igb_adapter *adapter, u64 *data)
{
- u16 temp;
- u16 checksum = 0;
- u16 i;
-
*data = 0;
- /* Read and add up the contents of the EEPROM */
- for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
- if ((adapter->hw.nvm.ops.read(&adapter->hw, i, 1, &temp)) < 0) {
- *data = 1;
- break;
- }
- checksum += temp;
- }
- /* If Checksum is not Correct return error else test passed */
- if ((checksum != (u16) NVM_SUM) && !(*data))
- *data = 2;
+ /* Validate eeprom on all parts but i211 */
+ if (adapter->hw.mac.type != e1000_i211) {
+ if (adapter->hw.nvm.ops.validate(&adapter->hw) < 0)
+ *data = 2;
+ }
return *data;
}
@@ -1240,6 +1271,8 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
ics_mask = 0x77DCFED5;
break;
case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
ics_mask = 0x77DCFED5;
break;
default:
@@ -1407,23 +1440,35 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 ctrl_reg = 0;
+ u16 phy_reg = 0;
hw->mac.autoneg = false;
- if (hw->phy.type == e1000_phy_m88) {
+ switch (hw->phy.type) {
+ case e1000_phy_m88:
/* Auto-MDI/MDIX Off */
igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
/* reset to update Auto-MDI/MDIX */
igb_write_phy_reg(hw, PHY_CONTROL, 0x9140);
/* autoneg off */
igb_write_phy_reg(hw, PHY_CONTROL, 0x8140);
- } else if (hw->phy.type == e1000_phy_82580) {
+ break;
+ case e1000_phy_82580:
/* enable MII loopback */
igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041);
+ break;
+ case e1000_phy_i210:
+ /* set loopback speed in PHY */
+ igb_read_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2),
+ &phy_reg);
+ phy_reg |= GS40G_MAC_SPEED_1G;
+ igb_write_phy_reg(hw, (GS40G_PAGE_SELECT & GS40G_PAGE_2),
+ phy_reg);
+ ctrl_reg = rd32(E1000_CTRL_EXT);
+ default:
+ break;
}
- ctrl_reg = rd32(E1000_CTRL);
-
/* force 1000, set loopback */
igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
@@ -1436,7 +1481,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
E1000_CTRL_FD | /* Force Duplex to FULL */
E1000_CTRL_SLU); /* Set link up enable bit */
- if (hw->phy.type == e1000_phy_m88)
+ if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210))
ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
wr32(E1000_CTRL, ctrl_reg);
@@ -1444,7 +1489,7 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
/* Disable the receiver on the PHY so when a cable is plugged in, the
* PHY does not begin to autoneg when a cable is reconnected to the NIC.
*/
- if (hw->phy.type == e1000_phy_m88)
+ if ((hw->phy.type == e1000_phy_m88) || (hw->phy.type == e1000_phy_i210))
igb_phy_disable_receiver(adapter);
udelay(500);
@@ -1703,6 +1748,14 @@ static int igb_loopback_test(struct igb_adapter *adapter, u64 *data)
*data = 0;
goto out;
}
+ if ((adapter->hw.mac.type == e1000_i210)
+ || (adapter->hw.mac.type == e1000_i210)) {
+ dev_err(&adapter->pdev->dev,
+ "Loopback test not supported "
+ "on this part at this time.\n");
+ *data = 0;
+ goto out;
+ }
*data = igb_setup_desc_rings(adapter);
if (*data)
goto out;
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 40d4c405fd7e..3b1aa4e15df8 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -50,6 +50,7 @@
#ifdef CONFIG_IGB_DCA
#include <linux/dca.h>
#endif
+#include <linux/ctype.h>
#include "igb.h"
#define MAJ 3
@@ -67,7 +68,15 @@ static const struct e1000_info *igb_info_tbl[] = {
[board_82575] = &e1000_82575_info,
};
+static char g_mac_addr[ETH_ALEN];
+static int g_usr_mac = 0;
+
static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SGMII), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES), board_82575 },
@@ -255,6 +264,40 @@ static const struct igb_reg_info igb_reg_info_tbl[] = {
{}
};
+/* Retrieve user set MAC address */
+static int __init setup_igb_mac(char *macstr)
+{
+ int i, j;
+ unsigned char result, value;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ result = 0;
+
+ if (i != 5 && *(macstr + 2) != ':')
+ return -1;
+
+ for (j = 0; j < 2; j++) {
+ if (isxdigit(*macstr)
+ && (value =
+ isdigit(*macstr) ? *macstr -
+ '0' : toupper(*macstr) - 'A' + 10) < 16) {
+ result = result * 16 + value;
+ macstr++;
+ } else
+ return -1;
+ }
+
+ macstr++;
+ g_mac_addr[i] = result;
+ }
+
+ g_usr_mac = 1;
+
+ return 0;
+}
+
+__setup("igb_mac=", setup_igb_mac);
+
/*
* igb_regdump - register printout routine
*/
@@ -647,6 +690,8 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
case e1000_82575:
case e1000_82580:
case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
default:
for (; i < adapter->num_rx_queues; i++)
adapter->rx_ring[i]->reg_idx = rbase_offset + i;
@@ -711,6 +756,14 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
/* set flag indicating ring supports SCTP checksum offload */
if (adapter->hw.mac.type >= e1000_82576)
ring->flags |= IGB_RING_FLAG_RX_SCTP_CSUM;
+
+ /*
+ * On i350, i210, and i211, loopback VLAN packets
+ * have the tag byte-swapped.
+ * */
+ if (adapter->hw.mac.type >= e1000_i350)
+ ring->flags |= IGB_RING_FLAG_RX_LB_VLAN_BSWAP;
+
adapter->rx_ring[i] = ring;
}
@@ -791,6 +844,8 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
break;
case e1000_82580:
case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
/* 82580 uses the same table-based approach as 82576 but has fewer
entries as a result we carry over for queues greater than 4. */
if (rx_queue > IGB_N0_QUEUE) {
@@ -872,6 +927,8 @@ static void igb_configure_msix(struct igb_adapter *adapter)
case e1000_82576:
case e1000_82580:
case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
/* Turn on MSI-X capability first, or our settings
* won't stick. And it will take days to debug. */
wr32(E1000_GPIE, E1000_GPIE_MSIX_MODE |
@@ -1018,6 +1075,11 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter)
if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS))
numvecs += adapter->num_tx_queues;
+ /* i210 and i211 can only have 4 MSIX vectors for rx/tx queues. */
+ if ((adapter->hw.mac.type == e1000_i210)
+ || (adapter->hw.mac.type == e1000_i211))
+ numvecs = 4;
+
/* store the number of vectors reserved for queues */
adapter->num_q_vectors = numvecs;
@@ -1025,6 +1087,7 @@ static int igb_set_interrupt_capability(struct igb_adapter *adapter)
numvecs++;
adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry),
GFP_KERNEL);
+
if (!adapter->msix_entries)
goto msi_only;
@@ -1599,6 +1662,8 @@ void igb_reset(struct igb_adapter *adapter)
pba &= E1000_RXPBS_SIZE_MASK_82576;
break;
case e1000_82575:
+ case e1000_i210:
+ case e1000_i211:
default:
pba = E1000_PBA_34K;
break;
@@ -1839,7 +1904,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
*/
if (pdev->is_virtfn) {
WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n",
- pci_name(pdev), pdev->vendor, pdev->device);
+ pci_name(pdev), pdev->vendor, pdev->device);
return -EINVAL;
}
@@ -1979,17 +2044,39 @@ static int __devinit igb_probe(struct pci_dev *pdev,
* known good starting state */
hw->mac.ops.reset_hw(hw);
- /* make sure the NVM is good */
- if (hw->nvm.ops.validate(hw) < 0) {
- dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n");
- err = -EIO;
- goto err_eeprom;
+#ifndef CONFIG_MACH_APALIS_T30
+/* Hack: skip NVM validation on Apalis T30 for now */
+ /*
+ * make sure the NVM is good , i211 parts have special NVM that
+ * doesn't contain a checksum
+ */
+ if (hw->mac.type != e1000_i211) {
+ if (hw->nvm.ops.validate(hw) < 0) {
+ dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n");
+ err = -EIO;
+ goto err_eeprom;
+ }
}
+#endif /* CONFIG_MACH_APALIS_T30 */
/* copy the MAC address out of the NVM */
if (hw->mac.ops.read_mac_addr(hw))
dev_err(&pdev->dev, "NVM Read Error\n");
+#ifdef CONFIG_MACH_APALIS_T30
+ if (g_usr_mac && (g_usr_mac < 3)) {
+ /* Get user set MAC address */
+ if (g_usr_mac == 2) {
+ /* 0x100000 offset for 2nd Ethernet MAC */
+ g_mac_addr[3] += 0x10;
+ if (g_mac_addr[3] < 0x10)
+ dev_warn(&pdev->dev, "MAC address byte 3 (0x%02x) wrap around", g_mac_addr[3]);
+ }
+ memcpy(hw->mac.addr, g_mac_addr, ETH_ALEN);
+ g_usr_mac++;
+ } else dev_warn(&pdev->dev, "using default igb MAC");
+#endif /* CONFIG_MACH_APALIS_T30 */
+
memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
memcpy(netdev->perm_addr, hw->mac.addr, netdev->addr_len);
@@ -2117,6 +2204,8 @@ static int __devinit igb_probe(struct pci_dev *pdev,
adapter->num_rx_queues, adapter->num_tx_queues);
switch (hw->mac.type) {
case e1000_i350:
+ case e1000_i210:
+ case e1000_i211:
igb_set_eee_i350(hw);
break;
default:
@@ -2231,11 +2320,17 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter)
{
#ifdef CONFIG_PCI_IOV
struct pci_dev *pdev = adapter->pdev;
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* Virtualization features not supported on i210 family. */
+ if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
+ return;
if (adapter->vfs_allocated_count) {
adapter->vf_data = kcalloc(adapter->vfs_allocated_count,
sizeof(struct vf_data_storage),
GFP_KERNEL);
+
/* if allocation failed then we do not support SR-IOV */
if (!adapter->vf_data) {
adapter->vfs_allocated_count = 0;
@@ -2409,11 +2504,28 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
} else
adapter->vfs_allocated_count = max_vfs;
break;
+ case e1000_i210:
+ case e1000_i211:
+ adapter->vfs_allocated_count = 0;
+ break;
default:
break;
}
#endif /* CONFIG_PCI_IOV */
- adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus());
+ switch (hw->mac.type) {
+ case e1000_i210:
+ adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I210,
+ num_online_cpus());
+ break;
+ case e1000_i211:
+ adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES_I211,
+ num_online_cpus());
+ break;
+ default:
+ adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES,
+ num_online_cpus());
+ break;
+ }
/* i350 cannot do RSS and SR-IOV at the same time */
if (hw->mac.type == e1000_i350 && adapter->vfs_allocated_count)
adapter->rss_queues = 1;
@@ -2438,7 +2550,7 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
/* Explicitly disable IRQ since the NIC can be in any state. */
igb_irq_disable(adapter);
- if (hw->mac.type == e1000_i350)
+ if (hw->mac.type >= e1000_i350)
adapter->flags &= ~IGB_FLAG_DMAC;
set_bit(__IGB_DOWN, &adapter->state);
@@ -2852,6 +2964,17 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
/* Don't need to set TUOFL or IPOFL, they default to 1 */
wr32(E1000_RXCSUM, rxcsum);
+ /*
+ * Generate RSS hash based on TCP port numbers and/or
+ * IPv4/v6 src and dst addresses since UDP cannot be
+ * hashed reliably due to IP fragmentation
+ */
+
+ mrqc = E1000_MRQC_RSS_FIELD_IPV4 |
+ E1000_MRQC_RSS_FIELD_IPV4_TCP |
+ E1000_MRQC_RSS_FIELD_IPV6 |
+ E1000_MRQC_RSS_FIELD_IPV6_TCP |
+ E1000_MRQC_RSS_FIELD_IPV6_TCP_EX;
/* If VMDq is enabled then we set the appropriate mode for that, else
* we default to RSS so that an RSS hash is calculated per packet even
@@ -2867,25 +2990,15 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
wr32(E1000_VT_CTL, vtctl);
}
if (adapter->rss_queues > 1)
- mrqc = E1000_MRQC_ENABLE_VMDQ_RSS_2Q;
+ mrqc |= E1000_MRQC_ENABLE_VMDQ_RSS_2Q;
else
- mrqc = E1000_MRQC_ENABLE_VMDQ;
+ mrqc |= E1000_MRQC_ENABLE_VMDQ;
} else {
- mrqc = E1000_MRQC_ENABLE_RSS_4Q;
+ if (hw->mac.type != e1000_i211)
+ mrqc |= E1000_MRQC_ENABLE_RSS_4Q;
}
igb_vmm_control(adapter);
- /*
- * Generate RSS hash based on TCP port numbers and/or
- * IPv4/v6 src and dst addresses since UDP cannot be
- * hashed reliably due to IP fragmentation
- */
- mrqc |= E1000_MRQC_RSS_FIELD_IPV4 |
- E1000_MRQC_RSS_FIELD_IPV4_TCP |
- E1000_MRQC_RSS_FIELD_IPV6 |
- E1000_MRQC_RSS_FIELD_IPV6_TCP |
- E1000_MRQC_RSS_FIELD_IPV6_TCP_EX;
-
wr32(E1000_MRQC, mrqc);
}
@@ -3484,7 +3597,7 @@ static void igb_set_rx_mode(struct net_device *netdev)
* we will have issues with VLAN tag stripping not being done for frames
* that are only arriving because we are the default pool
*/
- if (hw->mac.type < e1000_82576)
+ if ((hw->mac.type < e1000_82576) || (hw->mac.type > e1000_i350))
return;
vmolr |= rd32(E1000_VMOLR(vfn)) &
@@ -3581,7 +3694,7 @@ static bool igb_thermal_sensor_event(struct e1000_hw *hw, u32 event)
bool ret = false;
u32 ctrl_ext, thstat;
- /* check for thermal sensor event on i350, copper only */
+ /* check for thermal sensor event on i350 copper only */
if (hw->mac.type == e1000_i350) {
thstat = rd32(E1000_THSTAT);
ctrl_ext = rd32(E1000_CTRL_EXT);
@@ -6858,6 +6971,8 @@ static void igb_vmm_control(struct igb_adapter *adapter)
switch (hw->mac.type) {
case e1000_82575:
+ case e1000_i210:
+ case e1000_i211:
default:
/* replication is not supported for 82575 */
return;
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 710557700095..f2d5822338d7 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1,8 +1,7 @@
/*
* ASIX AX8817X based USB 2.0 Ethernet Devices
- * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
* Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
- * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
* Copyright (c) 2002-2003 TiVo Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -20,11 +19,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-// #define DEBUG // error path messages, extra info
-// #define VERBOSE // more; success messages
+//#define DEBUG // debug messages, extra info
+#include <linux/version.h>
+//#include <linux/config.h>
+#ifdef CONFIG_USB_DEBUG
+# define DEBUG
+#endif
#include <linux/module.h>
#include <linux/kmod.h>
+#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -33,690 +37,863 @@
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/crc32.h>
-#include <linux/usb/usbnet.h>
-#include <linux/slab.h>
-#define DRIVER_VERSION "14-Jun-2006"
-static const char driver_name [] = "asix";
-
-/* ASIX AX8817X based USB 2.0 Ethernet Devices */
+#include "axusbnet.c"
+#include "asix.h"
+
+#define DRV_VERSION "4.4.0"
+
+static char version[] =
+KERN_INFO "ASIX USB Ethernet Adapter:v" DRV_VERSION
+ " " __TIME__ " " __DATE__ "\n"
+KERN_INFO " http://www.asix.com.tw\n";
+
+static char g_mac_addr[ETH_ALEN];
+static int g_usr_mac = 0;
+
+/* configuration of maximum bulk in size */
+static int bsize = AX88772B_MAX_BULKIN_16K;
+module_param (bsize, int, 0);
+MODULE_PARM_DESC (bsize, "Maximum transfer size per bulk");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void ax88772b_link_reset (void *data);
+static void ax88772a_link_reset (void *data);
+static void ax88772_link_reset (void *data);
+#else
+static void ax88772b_link_reset (struct work_struct *work);
+static void ax88772a_link_reset (struct work_struct *work);
+static void ax88772_link_reset (struct work_struct *work);
+#endif
+static int ax88772a_phy_powerup (struct usbnet *dev);
+
+/* Retrieve user set MAC address */
+static int __init setup_asix_mac(char *macstr)
+{
+ int i, j;
+ unsigned char result, value;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ result = 0;
+
+ if (i != 5 && *(macstr + 2) != ':')
+ return -1;
+
+ for (j = 0; j < 2; j++) {
+ if (isxdigit(*macstr)
+ && (value =
+ isdigit(*macstr) ? *macstr -
+ '0' : toupper(*macstr) - 'A' + 10) < 16) {
+ result = result * 16 + value;
+ macstr++;
+ } else
+ return -1;
+ }
-#define AX_CMD_SET_SW_MII 0x06
-#define AX_CMD_READ_MII_REG 0x07
-#define AX_CMD_WRITE_MII_REG 0x08
-#define AX_CMD_SET_HW_MII 0x0a
-#define AX_CMD_READ_EEPROM 0x0b
-#define AX_CMD_WRITE_EEPROM 0x0c
-#define AX_CMD_WRITE_ENABLE 0x0d
-#define AX_CMD_WRITE_DISABLE 0x0e
-#define AX_CMD_READ_RX_CTL 0x0f
-#define AX_CMD_WRITE_RX_CTL 0x10
-#define AX_CMD_READ_IPG012 0x11
-#define AX_CMD_WRITE_IPG0 0x12
-#define AX_CMD_WRITE_IPG1 0x13
-#define AX_CMD_READ_NODE_ID 0x13
-#define AX_CMD_WRITE_NODE_ID 0x14
-#define AX_CMD_WRITE_IPG2 0x14
-#define AX_CMD_WRITE_MULTI_FILTER 0x16
-#define AX88172_CMD_READ_NODE_ID 0x17
-#define AX_CMD_READ_PHY_ID 0x19
-#define AX_CMD_READ_MEDIUM_STATUS 0x1a
-#define AX_CMD_WRITE_MEDIUM_MODE 0x1b
-#define AX_CMD_READ_MONITOR_MODE 0x1c
-#define AX_CMD_WRITE_MONITOR_MODE 0x1d
-#define AX_CMD_READ_GPIOS 0x1e
-#define AX_CMD_WRITE_GPIOS 0x1f
-#define AX_CMD_SW_RESET 0x20
-#define AX_CMD_SW_PHY_STATUS 0x21
-#define AX_CMD_SW_PHY_SELECT 0x22
-
-#define AX_MONITOR_MODE 0x01
-#define AX_MONITOR_LINK 0x02
-#define AX_MONITOR_MAGIC 0x04
-#define AX_MONITOR_HSFS 0x10
-
-/* AX88172 Medium Status Register values */
-#define AX88172_MEDIUM_FD 0x02
-#define AX88172_MEDIUM_TX 0x04
-#define AX88172_MEDIUM_FC 0x10
-#define AX88172_MEDIUM_DEFAULT \
- ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC )
-
-#define AX_MCAST_FILTER_SIZE 8
-#define AX_MAX_MCAST 64
-
-#define AX_SWRESET_CLEAR 0x00
-#define AX_SWRESET_RR 0x01
-#define AX_SWRESET_RT 0x02
-#define AX_SWRESET_PRTE 0x04
-#define AX_SWRESET_PRL 0x08
-#define AX_SWRESET_BZ 0x10
-#define AX_SWRESET_IPRL 0x20
-#define AX_SWRESET_IPPD 0x40
-
-#define AX88772_IPG0_DEFAULT 0x15
-#define AX88772_IPG1_DEFAULT 0x0c
-#define AX88772_IPG2_DEFAULT 0x12
-
-/* AX88772 & AX88178 Medium Mode Register */
-#define AX_MEDIUM_PF 0x0080
-#define AX_MEDIUM_JFE 0x0040
-#define AX_MEDIUM_TFC 0x0020
-#define AX_MEDIUM_RFC 0x0010
-#define AX_MEDIUM_ENCK 0x0008
-#define AX_MEDIUM_AC 0x0004
-#define AX_MEDIUM_FD 0x0002
-#define AX_MEDIUM_GM 0x0001
-#define AX_MEDIUM_SM 0x1000
-#define AX_MEDIUM_SBP 0x0800
-#define AX_MEDIUM_PS 0x0200
-#define AX_MEDIUM_RE 0x0100
-
-#define AX88178_MEDIUM_DEFAULT \
- (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
- AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
- AX_MEDIUM_RE )
-
-#define AX88772_MEDIUM_DEFAULT \
- (AX_MEDIUM_FD | AX_MEDIUM_RFC | \
- AX_MEDIUM_TFC | AX_MEDIUM_PS | \
- AX_MEDIUM_AC | AX_MEDIUM_RE )
-
-/* AX88772 & AX88178 RX_CTL values */
-#define AX_RX_CTL_SO 0x0080
-#define AX_RX_CTL_AP 0x0020
-#define AX_RX_CTL_AM 0x0010
-#define AX_RX_CTL_AB 0x0008
-#define AX_RX_CTL_SEP 0x0004
-#define AX_RX_CTL_AMALL 0x0002
-#define AX_RX_CTL_PRO 0x0001
-#define AX_RX_CTL_MFB_2048 0x0000
-#define AX_RX_CTL_MFB_4096 0x0100
-#define AX_RX_CTL_MFB_8192 0x0200
-#define AX_RX_CTL_MFB_16384 0x0300
-
-#define AX_DEFAULT_RX_CTL \
- (AX_RX_CTL_SO | AX_RX_CTL_AB )
-
-/* GPIO 0 .. 2 toggles */
-#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */
-#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */
-#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */
-#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */
-#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */
-#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */
-#define AX_GPIO_RESERVED 0x40 /* Reserved */
-#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */
-
-#define AX_EEPROM_MAGIC 0xdeadbeef
-#define AX88172_EEPROM_LEN 0x40
-#define AX88772_EEPROM_LEN 0xff
-
-#define PHY_MODE_MARVELL 0x0000
-#define MII_MARVELL_LED_CTRL 0x0018
-#define MII_MARVELL_STATUS 0x001b
-#define MII_MARVELL_CTRL 0x0014
-
-#define MARVELL_LED_MANUAL 0x0019
-
-#define MARVELL_STATUS_HWCFG 0x0004
-
-#define MARVELL_CTRL_TXDELAY 0x0002
-#define MARVELL_CTRL_RXDELAY 0x0080
-
-/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
-struct asix_data {
- u8 multi_filter[AX_MCAST_FILTER_SIZE];
- u8 mac_addr[ETH_ALEN];
- u8 phymode;
- u8 ledmode;
- u8 eeprom_len;
-};
+ macstr++;
+ g_mac_addr[i] = result;
+ }
-struct ax88172_int_data {
- __le16 res1;
- u8 link;
- __le16 res2;
- u8 status;
- __le16 res3;
-} __packed;
+ g_usr_mac = 1;
-static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
- u16 size, void *data)
-{
- void *buf;
- int err = -ENOMEM;
+ return 0;
+}
- netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
- cmd, value, index, size);
+__setup("asix_mac=", setup_asix_mac);
- buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- goto out;
+/* ASIX AX8817X based USB 2.0 Ethernet Devices */
- err = usb_control_msg(
+static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ return usb_control_msg(
dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
cmd,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value,
index,
- buf,
+ data,
size,
USB_CTRL_GET_TIMEOUT);
- if (err == size)
- memcpy(data, buf, size);
- else if (err >= 0)
- err = -EINVAL;
- kfree(buf);
-
-out:
- return err;
}
-static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
- void *buf = NULL;
- int err = -ENOMEM;
-
- netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
- cmd, value, index, size);
-
- if (data) {
- buf = kmemdup(data, size, GFP_KERNEL);
- if (!buf)
- goto out;
- }
-
- err = usb_control_msg(
+ return usb_control_msg(
dev->udev,
usb_sndctrlpipe(dev->udev, 0),
cmd,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value,
index,
- buf,
+ data,
size,
USB_CTRL_SET_TIMEOUT);
- kfree(buf);
-
-out:
- return err;
}
-static void asix_async_cmd_callback(struct urb *urb)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
+#else
+static void ax8817x_async_cmd_callback(struct urb *urb)
+#endif
{
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
- int status = urb->status;
- if (status < 0)
- printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d",
- status);
+ if (urb->status < 0)
+ printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d",
+ urb->status);
kfree(req);
usb_free_urb(urb);
}
-static void
-asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
- u16 size, void *data)
+static int ax8817x_set_mac_addr (struct net_device *net, void *p)
{
- struct usb_ctrlrequest *req;
- int status;
- struct urb *urb;
+ struct usbnet *dev = netdev_priv(net);
+ struct sockaddr *addr = p;
- netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n",
- cmd, value, index, size);
- if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
- netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n");
+ memcpy (net->dev_addr, addr->sa_data, ETH_ALEN);
+
+ /* Set the MAC address */
+ return ax8817x_write_cmd (dev, AX88772_CMD_WRITE_NODE_ID,
+ 0, 0, ETH_ALEN, net->dev_addr);
+
+}
+
+static void ax88178_status(struct usbnet *dev, struct urb *urb)
+{
+ struct ax88172_int_data *event;
+ struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv;
+ int link;
+
+ if (urb->actual_length < 8)
return;
- }
- if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
- netdev_err(dev->net, "Failed to allocate memory for control request\n");
- usb_free_urb(urb);
+ if (ax178dataptr->EepromData == PHY_MODE_MAC_TO_MAC_GMII)
return;
+
+ event = urb->transfer_buffer;
+ link = event->link & 0x01;
+ if (netif_carrier_ok(dev->net) != link) {
+ if (link) {
+ netif_carrier_on(dev->net);
+ axusbnet_defer_kevent (dev, EVENT_LINK_RESET);
+ } else
+ netif_carrier_off(dev->net);
+ devwarn(dev, "ax88178 - Link status is: %d", link);
}
+}
- req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- req->bRequest = cmd;
- req->wValue = cpu_to_le16(value);
- req->wIndex = cpu_to_le16(index);
- req->wLength = cpu_to_le16(size);
+static void ax8817x_status(struct usbnet *dev, struct urb *urb)
+{
+ struct ax88172_int_data *event;
+ int link;
- usb_fill_control_urb(urb, dev->udev,
- usb_sndctrlpipe(dev->udev, 0),
- (void *)req, data, size,
- asix_async_cmd_callback, req);
+ if (urb->actual_length < 8)
+ return;
- if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- netdev_err(dev->net, "Error submitting the control message: status=%d\n",
- status);
- kfree(req);
- usb_free_urb(urb);
+ event = urb->transfer_buffer;
+ link = event->link & 0x01;
+ if (netif_carrier_ok(dev->net) != link) {
+ if (link) {
+ netif_carrier_on(dev->net);
+ axusbnet_defer_kevent (dev, EVENT_LINK_RESET );
+ } else
+ netif_carrier_off(dev->net);
+ devwarn(dev, "ax8817x - Link status is: %d", link);
}
}
-static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+static void ax88772_status(struct usbnet *dev, struct urb *urb)
{
- u8 *head;
- u32 header;
- char *packet;
- struct sk_buff *ax_skb;
- u16 size;
+ struct ax88172_int_data *event;
+ struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv;
+ int link;
+
+ if (urb->actual_length < 8)
+ return;
- head = (u8 *) skb->data;
- memcpy(&header, head, sizeof(header));
- le32_to_cpus(&header);
- packet = head + sizeof(header);
+ event = urb->transfer_buffer;
+ link = event->link & 0x01;
+
+ if (netif_carrier_ok(dev->net) != link) {
+ if (link) {
+ netif_carrier_on(dev->net);
+ ax772_data->Event = AX_SET_RX_CFG;
+ } else {
+ netif_carrier_off(dev->net);
+ if (ax772_data->Event == AX_NOP) {
+ ax772_data->Event = PHY_POWER_DOWN;
+ ax772_data->TickToExpire = 25;
+ }
+ }
- skb_pull(skb, 4);
+ devwarn(dev, "ax88772 - Link status is: %d", link);
+ }
+
+ if (ax772_data->Event)
+ queue_work (ax772_data->ax_work, &ax772_data->check_link);
+}
- while (skb->len > 0) {
- if ((header & 0x07ff) != ((~header >> 16) & 0x07ff))
- netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
+static void ax88772a_status(struct usbnet *dev, struct urb *urb)
+{
+ struct ax88172_int_data *event;
+ struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv;
+ int link;
+ int PowSave = (ax772a_data->EepromData >> 14);
- /* get the packet length */
- size = (u16) (header & 0x000007ff);
+ if (urb->actual_length < 8)
+ return;
- if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
- u8 alignment = (unsigned long)skb->data & 0x3;
- if (alignment != 0x2) {
- /*
- * not 16bit aligned so use the room provided by
- * the 32 bit header to align the data
- *
- * note we want 16bit alignment as MAC header is
- * 14bytes thus ip header will be aligned on
- * 32bit boundary so accessing ipheader elements
- * using a cast to struct ip header wont cause
- * an unaligned accesses.
- */
- u8 realignment = (alignment + 2) & 0x3;
- memmove(skb->data - realignment,
- skb->data,
- size);
- skb->data -= realignment;
- skb_set_tail_pointer(skb, size);
- }
- return 2;
- }
+ event = urb->transfer_buffer;
+ link = event->link & 0x01;
- if (size > dev->net->mtu + ETH_HLEN) {
- netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
- size);
- return 0;
- }
- ax_skb = skb_clone(skb, GFP_ATOMIC);
- if (ax_skb) {
- u8 alignment = (unsigned long)packet & 0x3;
- ax_skb->len = size;
+ if (netif_carrier_ok(dev->net) != link) {
- if (alignment != 0x2) {
- /*
- * not 16bit aligned use the room provided by
- * the 32 bit header to align the data
- */
- u8 realignment = (alignment + 2) & 0x3;
- memmove(packet - realignment, packet, size);
- packet -= realignment;
+ if (link) {
+ netif_carrier_on(dev->net);
+ ax772a_data->Event = AX_SET_RX_CFG;
+ } else if ((PowSave == 0x3) || (PowSave == 0x1)) {
+ netif_carrier_off(dev->net);
+ if (ax772a_data->Event == AX_NOP) {
+ ax772a_data->Event = CHK_CABLE_EXIST;
+ ax772a_data->TickToExpire = 14;
}
- ax_skb->data = packet;
- skb_set_tail_pointer(ax_skb, size);
- usbnet_skb_return(dev, ax_skb);
} else {
- return 0;
+ netif_carrier_off(dev->net);
+ ax772a_data->Event = AX_NOP;
}
- skb_pull(skb, (size + 1) & 0xfffe);
-
- if (skb->len < sizeof(header))
- break;
-
- head = (u8 *) skb->data;
- memcpy(&header, head, sizeof(header));
- le32_to_cpus(&header);
- packet = head + sizeof(header);
- skb_pull(skb, 4);
- }
-
- if (skb->len < 0) {
- netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n",
- skb->len);
- return 0;
+ devwarn(dev, "ax88772a - Link status is: %d", link);
}
- return 1;
+
+ if (ax772a_data->Event)
+ queue_work (ax772a_data->ax_work, &ax772a_data->check_link);
}
-static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
- gfp_t flags)
+static int ax88772b_stop(struct usbnet *dev)
{
- int padlen;
- int headroom = skb_headroom(skb);
- int tailroom = skb_tailroom(skb);
- u32 packet_len;
- u32 padbytes = 0xffff0000;
+ u16 *medium;
- padlen = ((skb->len + 4) % 512) ? 0 : 4;
+ medium = kmalloc (2, GFP_ATOMIC);
+ if (medium) {
+ ax8817x_read_cmd (dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, medium);
+ ax8817x_write_cmd (dev, AX_CMD_WRITE_MEDIUM_MODE,
+ (*medium & ~AX88772_MEDIUM_RX_ENABLE), 0, 0, NULL);
- if ((!skb_cloned(skb)) &&
- ((headroom + tailroom) >= (4 + padlen))) {
- if ((headroom < 4) || (tailroom < padlen)) {
- skb->data = memmove(skb->head + 4, skb->data, skb->len);
- skb_set_tail_pointer(skb, skb->len);
- }
- } else {
- struct sk_buff *skb2;
- skb2 = skb_copy_expand(skb, 4, padlen, flags);
- dev_kfree_skb_any(skb);
- skb = skb2;
- if (!skb)
- return NULL;
+ kfree (medium);
+ return 0;
}
+ return -EINVAL;
+
+}
- skb_push(skb, 4);
- packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
- cpu_to_le32s(&packet_len);
- skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
+static int ax88772b_reset(struct usbnet *dev)
+{
+ int ret;
- if ((skb->len % 512) == 0) {
- cpu_to_le32s(&padbytes);
- memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
- skb_put(skb, sizeof(padbytes));
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+ AX88772_MEDIUM_DEFAULT, 0, 0, NULL)) < 0) {
+ deverr(dev, "Write medium mode register: %d", ret);
}
- return skb;
+ return ret;
+
}
-static void asix_status(struct usbnet *dev, struct urb *urb)
+
+static void ax88772b_status(struct usbnet *dev, struct urb *urb)
{
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
struct ax88172_int_data *event;
int link;
if (urb->actual_length < 8)
return;
+ if (ax772b_data->OperationMode == OPERATION_PHY_MODE)
+ return;
+
event = urb->transfer_buffer;
- link = event->link & 0x01;
+ if (ax772b_data->PhySelect == 0 && ax772b_data->OperationMode
+ == OPERATION_MAC_MODE)
+ link = event->link & AX_INT_SPLS_LINK;
+ else
+ link = event->link & AX_INT_PPLS_LINK;
+
if (netif_carrier_ok(dev->net) != link) {
if (link) {
netif_carrier_on(dev->net);
- usbnet_defer_kevent (dev, EVENT_LINK_RESET );
- } else
+ ax772b_data->Event = AX_SET_RX_CFG;
+ } else {
netif_carrier_off(dev->net);
- netdev_dbg(dev->net, "Link Status is: %d\n", link);
+ ax772b_data->time_to_chk = jiffies;
+ }
+ devwarn(dev, "ax88772b - Link status is: %d", link);
}
-}
-
-static inline int asix_set_sw_mii(struct usbnet *dev)
-{
- int ret;
- ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
- if (ret < 0)
- netdev_err(dev->net, "Failed to enable software MII access\n");
- return ret;
-}
-static inline int asix_set_hw_mii(struct usbnet *dev)
-{
- int ret;
- ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
- if (ret < 0)
- netdev_err(dev->net, "Failed to enable hardware MII access\n");
- return ret;
-}
+ if (!link) {
-static inline int asix_get_phy_addr(struct usbnet *dev)
-{
- u8 buf[2];
- int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
-
- netdev_dbg(dev->net, "asix_get_phy_addr()\n");
+ int no_cable = (event->link & AX_INT_CABOFF_UNPLUG) ? 1 : 0;
- if (ret < 0) {
- netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
- goto out;
+ if (no_cable) {
+ if ((ax772b_data->psc &
+ (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) &&
+ !ax772b_data->pw_enabled) {
+ /*
+ * AX88772B already entered power saving state
+ */
+ ax772b_data->pw_enabled = 1;
+ }
+/* Disable failing auto detach stuff for now */
+#if 0
+ ax772b_data->Event = AX_CHK_AUTODETACH;
+#endif
+ } else {
+ /* AX88772B resumed from power saving state */
+ if (ax772b_data->pw_enabled ||
+ (jiffies > (ax772b_data->time_to_chk +
+ AX88772B_WATCHDOG))) {
+ if (ax772b_data->pw_enabled)
+ ax772b_data->pw_enabled = 0;
+ ax772b_data->Event = PHY_POWER_UP;
+ ax772b_data->time_to_chk = jiffies;
+ }
+ }
}
- netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
- *((__le16 *)buf));
- ret = buf[1];
-out:
- return ret;
+ if (ax772b_data->Event)
+ queue_work (ax772b_data->ax_work, &ax772b_data->check_link);
}
-static int asix_sw_reset(struct usbnet *dev, u8 flags)
+void
+ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
{
- int ret;
+ struct usb_ctrlrequest *req;
+ int status;
+ struct urb *urb;
- ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
- if (ret < 0)
- netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
+ if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
+ deverr(dev, "Error allocating URB in write_cmd_async!");
+ return;
+ }
- return ret;
-}
+ if ((req = kmalloc (sizeof (struct usb_ctrlrequest),
+ GFP_ATOMIC)) == NULL) {
+ deverr(dev, "Failed to allocate memory for control request");
+ usb_free_urb(urb);
+ return;
+ }
-static u16 asix_read_rx_ctl(struct usbnet *dev)
-{
- __le16 v;
- int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v);
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ req->bRequest = cmd;
+ req->wValue = cpu_to_le16(value);
+ req->wIndex = cpu_to_le16(index);
+ req->wLength = cpu_to_le16(size);
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, data, size,
+ ax8817x_async_cmd_callback, req);
- if (ret < 0) {
- netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
- goto out;
+ if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ deverr(dev, "Error submitting the control message: status=%d",
+ status);
+ kfree(req);
+ usb_free_urb(urb);
}
- ret = le16_to_cpu(v);
-out:
- return ret;
}
-static int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
+static void ax8817x_set_multicast(struct net_device *net)
{
- int ret;
+ struct usbnet *dev = netdev_priv(net);
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+ u8 rx_ctl = AX_RX_CTL_START | AX_RX_CTL_AB;
+ int mc_count;
- netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
- ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
- if (ret < 0)
- netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
- mode, ret);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ mc_count = net->mc_count;
+#else
+ mc_count = netdev_mc_count (net);
+#endif
- return ret;
-}
+ if (net->flags & IFF_PROMISC) {
+ rx_ctl |= AX_RX_CTL_PRO;
+ } else if (net->flags & IFF_ALLMULTI
+ || mc_count > AX_MAX_MCAST) {
+ rx_ctl |= AX_RX_CTL_AMALL;
+ } else if (mc_count == 0) {
+ /* just broadcast and directed */
+ } else {
+ /* We use the 20 byte dev->data
+ * for our 8 byte filter buffer
+ * to avoid allocating memory that
+ * is tricky to free later */
+ u32 crc_bits;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ struct dev_mc_list *mc_list = net->mc_list;
+ int i;
-static u16 asix_read_medium_status(struct usbnet *dev)
-{
- __le16 v;
- int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
+
+ /* Build the multicast hash filter. */
+ for (i = 0; i < net->mc_count; i++) {
+ crc_bits =
+ ether_crc(ETH_ALEN,
+ mc_list->dmi_addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |=
+ 1 << (crc_bits & 7);
+ mc_list = mc_list->next;
+ }
+#else
+ struct netdev_hw_addr *ha;
+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
+ netdev_for_each_mc_addr (ha, net) {
+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |=
+ 1 << (crc_bits & 7);
+ }
+#endif
+ ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
+ AX_MCAST_FILTER_SIZE, data->multi_filter);
- if (ret < 0) {
- netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
- ret);
- goto out;
+ rx_ctl |= AX_RX_CTL_AM;
}
- ret = le16_to_cpu(v);
-out:
- return ret;
+
+ ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
}
-static int asix_write_medium_mode(struct usbnet *dev, u16 mode)
+static void ax88178_set_multicast(struct net_device *net)
{
- int ret;
+ struct usbnet *dev = netdev_priv(net);
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+ u16 rx_ctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_CTL_MFB);
+ int mc_count;
- netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
- ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
- if (ret < 0)
- netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
- mode, ret);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ mc_count = net->mc_count;
+#else
+ mc_count = netdev_mc_count (net);
+#endif
- return ret;
-}
+ if (net->flags & IFF_PROMISC) {
+ rx_ctl |= AX_RX_CTL_PRO;
+ } else if (net->flags & IFF_ALLMULTI
+ || mc_count > AX_MAX_MCAST) {
+ rx_ctl |= AX_RX_CTL_AMALL;
+ } else if (mc_count == 0) {
+ /* just broadcast and directed */
+ } else {
+ /* We use the 20 byte dev->data
+ * for our 8 byte filter buffer
+ * to avoid allocating memory that
+ * is tricky to free later */
+ u32 crc_bits;
-static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
-{
- int ret;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ struct dev_mc_list *mc_list = net->mc_list;
+ int i;
- netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
- ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
- if (ret < 0)
- netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
- value, ret);
+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
+
+ /* Build the multicast hash filter. */
+ for (i = 0; i < net->mc_count; i++) {
+ crc_bits =
+ ether_crc(ETH_ALEN,
+ mc_list->dmi_addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |=
+ 1 << (crc_bits & 7);
+ mc_list = mc_list->next;
+ }
+#else
+ struct netdev_hw_addr *ha;
+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
+ netdev_for_each_mc_addr (ha, net) {
+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |=
+ 1 << (crc_bits & 7);
+ }
+#endif
+ ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
+ AX_MCAST_FILTER_SIZE, data->multi_filter);
- if (sleep)
- msleep(sleep);
+ rx_ctl |= AX_RX_CTL_AM;
+ }
- return ret;
+ ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
}
-/*
- * AX88772 & AX88178 have a 16-bit RX_CTL value
- */
-static void asix_set_multicast(struct net_device *net)
+static void ax88772b_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
- struct asix_data *data = (struct asix_data *)&dev->data;
- u16 rx_ctl = AX_DEFAULT_RX_CTL;
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+ u16 rx_ctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_HEADER_DEFAULT);
+ int mc_count;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ mc_count = net->mc_count;
+#else
+ mc_count = netdev_mc_count (net);
+#endif
if (net->flags & IFF_PROMISC) {
rx_ctl |= AX_RX_CTL_PRO;
- } else if (net->flags & IFF_ALLMULTI ||
- netdev_mc_count(net) > AX_MAX_MCAST) {
+ } else if (net->flags & IFF_ALLMULTI
+ || mc_count > AX_MAX_MCAST) {
rx_ctl |= AX_RX_CTL_AMALL;
- } else if (netdev_mc_empty(net)) {
+ } else if (mc_count == 0) {
/* just broadcast and directed */
} else {
/* We use the 20 byte dev->data
* for our 8 byte filter buffer
* to avoid allocating memory that
* is tricky to free later */
- struct netdev_hw_addr *ha;
u32 crc_bits;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
+ struct dev_mc_list *mc_list = net->mc_list;
+ int i;
+
memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
/* Build the multicast hash filter. */
- netdev_for_each_mc_addr(ha, net) {
- crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ for (i = 0; i < net->mc_count; i++) {
+ crc_bits =
+ ether_crc(ETH_ALEN,
+ mc_list->dmi_addr) >> 26;
data->multi_filter[crc_bits >> 3] |=
1 << (crc_bits & 7);
+ mc_list = mc_list->next;
}
-
- asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
+#else
+ struct netdev_hw_addr *ha;
+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
+ netdev_for_each_mc_addr (ha, net) {
+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |=
+ 1 << (crc_bits & 7);
+ }
+#endif
+ ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
AX_MCAST_FILTER_SIZE, data->multi_filter);
rx_ctl |= AX_RX_CTL_AM;
}
- asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+ ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+}
+
+static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ u16 *res;
+ u16 ret;
+
+ res = kmalloc (2, GFP_ATOMIC);
+ if (!res)
+ return 0;
+
+ ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL);
+ ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, res);
+ ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL);
+
+ ret = *res & 0xffff;
+ kfree (res);
+
+ return ret;
}
-static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
+static int
+ax8817x_swmii_mdio_read(struct net_device *netdev, int phy_id, int loc)
{
struct usbnet *dev = netdev_priv(netdev);
- __le16 res;
+ u16 *res;
+ u16 ret;
+
+ res = kmalloc (2, GFP_ATOMIC);
+ if (!res)
+ return 0;
+
+ ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
+ (__u16)loc, 2, res);
- mutex_lock(&dev->phy_mutex);
- asix_set_sw_mii(dev);
- asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
- (__u16)loc, 2, &res);
- asix_set_hw_mii(dev);
- mutex_unlock(&dev->phy_mutex);
+ ret = *res & 0xffff;
+ kfree (res);
- netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
- phy_id, loc, le16_to_cpu(res));
+ return ret;
+}
- return le16_to_cpu(res);
+/* same as above, but converts resulting value to cpu byte order */
+static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc)
+{
+ return le16_to_cpu(ax8817x_mdio_read(netdev,phy_id, loc));
+}
+
+static int
+ax8817x_swmii_mdio_read_le(struct net_device *netdev, int phy_id, int loc)
+{
+ return le16_to_cpu(ax8817x_swmii_mdio_read(netdev,phy_id, loc));
}
static void
-asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
{
struct usbnet *dev = netdev_priv(netdev);
- __le16 res = cpu_to_le16(val);
+ u16 *res;
+
+ res = kmalloc (2, GFP_ATOMIC);
+ if (!res)
+ return;
+ *res = val;
+
+ ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL);
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
+ (__u16)loc, 2, res);
+ ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL);
- netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
- phy_id, loc, val);
- mutex_lock(&dev->phy_mutex);
- asix_set_sw_mii(dev);
- asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
- asix_set_hw_mii(dev);
- mutex_unlock(&dev->phy_mutex);
+ kfree (res);
}
-/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
-static u32 asix_get_phyid(struct usbnet *dev)
+static void ax8817x_swmii_mdio_write(struct net_device *netdev,
+ int phy_id, int loc, int val)
{
- int phy_reg;
- u32 phy_id;
+ struct usbnet *dev = netdev_priv(netdev);
+ u16 *res;
- phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
- if (phy_reg < 0)
- return 0;
+ res = kmalloc (2, GFP_ATOMIC);
+ if (!res)
+ return;
+ *res = val;
- phy_id = (phy_reg & 0xffff) << 16;
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
+ (__u16)loc, 2, res);
- phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
- if (phy_reg < 0)
- return 0;
+ kfree (res);
+}
+
+static void
+ax88772b_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ u16 *res;
+
+ res = kmalloc (2, GFP_ATOMIC);
+ if (!res)
+ return;
+ *res = val;
+
+ ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL);
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
+ (__u16)loc, 2, res);
+
+ if (loc == MII_ADVERTISE) {
+ *res = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART);
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
+ (__u16)MII_BMCR, 2, res);
+ }
+
+ ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL);
+
+ kfree (res);
+}
+
+/* same as above, but converts new value to le16 byte order before writing */
+static void
+ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val)
+{
+ ax8817x_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) );
+}
+
+static void ax8817x_swmii_mdio_write_le(struct net_device *netdev,
+ int phy_id, int loc, int val)
+{
+ ax8817x_swmii_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) );
+}
+
+static void
+ax88772b_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val)
+{
+ ax88772b_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) );
+}
+
+static int ax88772_suspend (struct usb_interface *intf,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
+ pm_message_t message)
+#else
+ u32 message)
+#endif
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ u16 *medium;
+
+ medium = kmalloc (2, GFP_ATOMIC);
+ if (!medium)
+ return axusbnet_suspend (intf, message);
+
+ ax8817x_read_cmd (dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, medium);
+ ax8817x_write_cmd (dev, AX_CMD_WRITE_MEDIUM_MODE,
+ (*medium & ~AX88772_MEDIUM_RX_ENABLE), 0, 0, NULL);
+
+ kfree (medium);
+ return axusbnet_suspend (intf, message);
+}
+
+static int ax88772b_suspend (struct usb_interface *intf,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
+ pm_message_t message)
+#else
+ u32 message)
+#endif
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
+ u16 *tmp16;
+ u8 *opt;
+
+ tmp16 = kmalloc (2, GFP_ATOMIC);
+ if (!tmp16)
+ return axusbnet_suspend (intf, message);
+ opt = (u8 *)tmp16;
+
+ ax8817x_read_cmd (dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, tmp16);
+ ax8817x_write_cmd (dev, AX_CMD_WRITE_MEDIUM_MODE,
+ (*tmp16 & ~AX88772_MEDIUM_RX_ENABLE), 0, 0, NULL);
+
+ ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, opt);
+ if (!(*opt & AX_MONITOR_LINK) && !(*opt & AX_MONITOR_MAGIC)) {
+ ax8817x_write_cmd (dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL | AX_SWRESET_IPPD, 0, 0, NULL);
+ } else {
+
+ if (ax772b_data->psc & AX_SWRESET_WOLLP) {
+ *tmp16 = ax8817x_mdio_read_le (dev->net,
+ dev->mii.phy_id, MII_BMCR);
+ ax8817x_mdio_write_le (dev->net, dev->mii.phy_id,
+ MII_BMCR, *tmp16 | BMCR_ANENABLE);
+
+ ax8817x_write_cmd (dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL | ax772b_data->psc, 0, 0, NULL);
+ }
+
+ if (ax772b_data->psc &
+ (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) {
+ *opt |= AX_MONITOR_LINK;
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
+ *opt, 0, 0, NULL);
+ }
+ }
+
+ kfree (tmp16);
+ return axusbnet_suspend (intf, message);
+}
- phy_id |= (phy_reg & 0xffff);
+static int ax88772_resume (struct usb_interface *intf)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+
+ netif_carrier_off (dev->net);
+
+ return axusbnet_resume (intf);
+}
+
+static int ax88772b_resume (struct usb_interface *intf)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
+
+ if (ax772b_data->psc & AX_SWRESET_WOLLP) {
+ ax8817x_write_cmd (dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL | (ax772b_data->psc & 0x7FFF),
+ 0, 0, NULL);
+ }
+
+ if (ax772b_data->psc & (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) {
+ ax88772a_phy_powerup (dev);
+ }
+
+ netif_carrier_off (dev->net);
+
+ return axusbnet_resume (intf);
+}
+
+static int ax88172_link_reset(struct usbnet *dev)
+{
+ u16 lpa;
+ u16 adv;
+ u16 res;
+ u8 mode;
+
+ mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN;
+ lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
+ adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
+ res = mii_nway_result(lpa|adv);
+ if (res & LPA_DUPLEX)
+ mode |= AX_MEDIUM_FULL_DUPLEX;
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
- return phy_id;
+ return 0;
}
static void
-asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
{
struct usbnet *dev = netdev_priv(net);
- u8 opt;
+ u8 *opt;
+
+ wolinfo->supported = 0;
+ wolinfo->wolopts = 0;
- if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
- wolinfo->supported = 0;
- wolinfo->wolopts = 0;
+ opt = kmalloc (1, GFP_KERNEL);
+ if (!opt)
return;
- }
+
+ if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, opt) < 0)
+ return;
+
wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
- wolinfo->wolopts = 0;
- if (opt & AX_MONITOR_MODE) {
- if (opt & AX_MONITOR_LINK)
- wolinfo->wolopts |= WAKE_PHY;
- if (opt & AX_MONITOR_MAGIC)
- wolinfo->wolopts |= WAKE_MAGIC;
- }
+
+ if (*opt & AX_MONITOR_LINK)
+ wolinfo->wolopts |= WAKE_PHY;
+ if (*opt & AX_MONITOR_MAGIC)
+ wolinfo->wolopts |= WAKE_MAGIC;
+
+ kfree (opt);
}
static int
-asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
{
struct usbnet *dev = netdev_priv(net);
- u8 opt = 0;
+ u8 *opt;
+
+ opt = kmalloc (1, GFP_KERNEL);
+ if (!opt)
+ return -ENOMEM;
+ *opt = 0;
if (wolinfo->wolopts & WAKE_PHY)
- opt |= AX_MONITOR_LINK;
+ *opt |= AX_MONITOR_LINK;
if (wolinfo->wolopts & WAKE_MAGIC)
- opt |= AX_MONITOR_MAGIC;
- if (opt != 0)
- opt |= AX_MONITOR_MODE;
+ *opt |= AX_MONITOR_MAGIC;
- if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
- opt, 0, 0, NULL) < 0)
- return -EINVAL;
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, *opt, 0, 0, NULL);
+ kfree (opt);
return 0;
}
-static int asix_get_eeprom_len(struct net_device *net)
+static int ax8817x_get_eeprom_len(struct net_device *net)
{
- struct usbnet *dev = netdev_priv(net);
- struct asix_data *data = (struct asix_data *)&dev->data;
-
- return data->eeprom_len;
+ return AX_EEPROM_LEN;
}
-static int asix_get_eeprom(struct net_device *net,
+static int ax8817x_get_eeprom(struct net_device *net,
struct ethtool_eeprom *eeprom, u8 *data)
{
struct usbnet *dev = netdev_priv(net);
- __le16 *ebuf = (__le16 *)data;
+ u16 *ebuf = (u16 *)data;
int i;
/* Crude hack to ensure that we don't overwrite memory
@@ -729,722 +906,2765 @@ static int asix_get_eeprom(struct net_device *net,
/* ax8817x returns 2 bytes from eeprom on read */
for (i=0; i < eeprom->len / 2; i++) {
- if (asix_read_cmd(dev, AX_CMD_READ_EEPROM,
+ if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM,
eeprom->offset + i, 0, 2, &ebuf[i]) < 0)
return -EINVAL;
}
return 0;
}
-static void asix_get_drvinfo (struct net_device *net,
+static void ax8817x_get_drvinfo (struct net_device *net,
struct ethtool_drvinfo *info)
{
- struct usbnet *dev = netdev_priv(net);
- struct asix_data *data = (struct asix_data *)&dev->data;
-
/* Inherit standard device info */
- usbnet_get_drvinfo(net, info);
- strncpy (info->driver, driver_name, sizeof info->driver);
- strncpy (info->version, DRIVER_VERSION, sizeof info->version);
- info->eedump_len = data->eeprom_len;
+ axusbnet_get_drvinfo(net, info);
+ info->eedump_len = 0x3e;
}
-static u32 asix_get_link(struct net_device *net)
+static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
+ return mii_ethtool_gset(&dev->mii,cmd);
+}
- return mii_link_ok(&dev->mii);
+static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+ return mii_ethtool_sset(&dev->mii,cmd);
}
-static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+/* We need to override some ethtool_ops so we require our
+ own structure so we don't interfere with other usbnet
+ devices that may be connected at the same time. */
+static struct ethtool_ops ax8817x_ethtool_ops = {
+ .get_drvinfo = ax8817x_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = axusbnet_get_msglevel,
+ .set_msglevel = axusbnet_set_msglevel,
+ .get_wol = ax8817x_get_wol,
+ .set_wol = ax8817x_set_wol,
+ .get_eeprom_len = ax8817x_get_eeprom_len,
+ .get_eeprom = ax8817x_get_eeprom,
+ .get_settings = ax8817x_get_settings,
+ .set_settings = ax8817x_set_settings,
+};
+
+static int ax8817x_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
{
struct usbnet *dev = netdev_priv(net);
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
-static int asix_set_mac_address(struct net_device *net, void *p)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)
+static const struct net_device_ops ax88x72_netdev_ops = {
+ .ndo_open = axusbnet_open,
+ .ndo_stop = axusbnet_stop,
+ .ndo_start_xmit = axusbnet_start_xmit,
+ .ndo_tx_timeout = axusbnet_tx_timeout,
+ .ndo_change_mtu = axusbnet_change_mtu,
+ .ndo_get_stats = axusbnet_get_stats,
+ .ndo_do_ioctl = ax8817x_ioctl,
+ .ndo_set_mac_address = ax8817x_set_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,2,0)
+ .ndo_set_multicast_list = ax8817x_set_multicast,
+#else
+ .ndo_set_rx_mode = ax8817x_set_multicast,
+#endif
+};
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)
+static const struct net_device_ops ax88178_netdev_ops = {
+ .ndo_open = axusbnet_open,
+ .ndo_stop = axusbnet_stop,
+ .ndo_start_xmit = axusbnet_start_xmit,
+ .ndo_tx_timeout = axusbnet_tx_timeout,
+ .ndo_change_mtu = axusbnet_change_mtu,
+ .ndo_get_stats = axusbnet_get_stats,
+ .ndo_do_ioctl = ax8817x_ioctl,
+ .ndo_set_mac_address = ax8817x_set_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,2,0)
+ .ndo_set_multicast_list = ax88178_set_multicast,
+#else
+ .ndo_set_rx_mode = ax88178_set_multicast,
+#endif
+};
+#endif
+
+static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf)
{
- struct usbnet *dev = netdev_priv(net);
- struct asix_data *data = (struct asix_data *)&dev->data;
- struct sockaddr *addr = p;
+ int ret = 0;
+ void *buf;
+ int i;
+ unsigned long gpio_bits = dev->driver_info->data;
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+
+ axusbnet_get_endpoints(dev,intf);
+
+ buf = kmalloc(ETH_ALEN, GFP_KERNEL);
+ if(!buf) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ /* Toggle the GPIOs in a manufacturer/model specific way */
+ for (i = 2; i >= 0; i--) {
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+ (gpio_bits >> (i * 8)) & 0xff, 0, 0,
+ NULL)) < 0)
+ goto out2;
+ msleep(5);
+ }
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ 0x80, 0, 0, NULL)) < 0) {
+ deverr(dev, "send AX_CMD_WRITE_RX_CTL failed: %d", ret);
+ goto out2;
+ }
+
+ /* Get the MAC address */
+ memset(buf, 0, ETH_ALEN);
+ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID,
+ 0, 0, 6, buf)) < 0) {
+ deverr(dev, "read AX_CMD_READ_NODE_ID failed: %d", ret);
+ goto out2;
+ }
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+ /* Get the PHY id */
+ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID,
+ 0, 0, 2, buf)) < 0) {
+ deverr(dev, "error on read AX_CMD_READ_PHY_ID: %02x", ret);
+ goto out2;
+ } else if (ret < 2) {
+ /* this should always return 2 bytes */
+ deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x",
+ ret);
+ ret = -EIO;
+ goto out2;
+ }
- if (netif_running(net))
- return -EBUSY;
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = ax8817x_mdio_read_le;
+ dev->mii.mdio_write = ax8817x_mdio_write_le;
+ dev->mii.phy_id_mask = 0x3f;
+ dev->mii.reg_num_mask = 0x1f;
+ dev->mii.phy_id = *((u8 *)buf + 1);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ dev->net->do_ioctl = ax8817x_ioctl;
+ dev->net->set_multicast_list = ax8817x_set_multicast;
+ dev->net->set_mac_address = ax8817x_set_mac_addr;
+#else
+ dev->net->netdev_ops = &ax88x72_netdev_ops;
+#endif
- memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
+ dev->net->ethtool_ops = &ax8817x_ethtool_ops;
+
+ /* Register suspend and resume functions */
+ data->suspend = axusbnet_suspend;
+ data->resume = axusbnet_resume;
+
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ mii_nway_restart(&dev->mii);
- /* We use the 20 byte dev->data
- * for our 6 byte mac buffer
- * to avoid allocating memory that
- * is tricky to free later */
- memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
- asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
- data->mac_addr);
+ printk (version);
return 0;
+out2:
+ kfree(buf);
+out1:
+ return ret;
}
-/* We need to override some ethtool_ops so we require our
- own structure so we don't interfere with other usbnet
- devices that may be connected at the same time. */
-static const struct ethtool_ops ax88172_ethtool_ops = {
- .get_drvinfo = asix_get_drvinfo,
- .get_link = asix_get_link,
- .get_msglevel = usbnet_get_msglevel,
- .set_msglevel = usbnet_set_msglevel,
- .get_wol = asix_get_wol,
- .set_wol = asix_set_wol,
- .get_eeprom_len = asix_get_eeprom_len,
- .get_eeprom = asix_get_eeprom,
- .get_settings = usbnet_get_settings,
- .set_settings = usbnet_set_settings,
- .nway_reset = usbnet_nway_reset,
+static struct ethtool_ops ax88772_ethtool_ops = {
+ .get_drvinfo = ax8817x_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = axusbnet_get_msglevel,
+ .set_msglevel = axusbnet_set_msglevel,
+ .get_wol = ax8817x_get_wol,
+ .set_wol = ax8817x_set_wol,
+ .get_eeprom_len = ax8817x_get_eeprom_len,
+ .get_eeprom = ax8817x_get_eeprom,
+ .get_settings = ax8817x_get_settings,
+ .set_settings = ax8817x_set_settings,
};
-static void ax88172_set_multicast(struct net_device *net)
+static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
- struct usbnet *dev = netdev_priv(net);
- struct asix_data *data = (struct asix_data *)&dev->data;
- u8 rx_ctl = 0x8c;
+ int ret;
+ void *buf;
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+ struct ax88772_data *ax772_data = NULL;
- if (net->flags & IFF_PROMISC) {
- rx_ctl |= 0x01;
- } else if (net->flags & IFF_ALLMULTI ||
- netdev_mc_count(net) > AX_MAX_MCAST) {
- rx_ctl |= 0x02;
- } else if (netdev_mc_empty(net)) {
- /* just broadcast and directed */
- } else {
- /* We use the 20 byte dev->data
- * for our 8 byte filter buffer
- * to avoid allocating memory that
- * is tricky to free later */
- struct netdev_hw_addr *ha;
- u32 crc_bits;
+ axusbnet_get_endpoints(dev,intf);
- memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
+ buf = kmalloc(6, GFP_KERNEL);
+ if(!buf) {
+ deverr(dev, "Cannot allocate memory for buffer");
+ ret = -ENOMEM;
+ goto out1;
+ }
- /* Build the multicast hash filter. */
- netdev_for_each_mc_addr(ha, net) {
- crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
- data->multi_filter[crc_bits >> 3] |=
- 1 << (crc_bits & 7);
+ ax772_data = kmalloc (sizeof(*ax772_data), GFP_KERNEL);
+ if (!ax772_data) {
+ deverr(dev, "Cannot allocate memory for AX88772 data");
+ kfree (buf);
+ return -ENOMEM;
+ }
+ memset (ax772_data, 0, sizeof(*ax772_data));
+ dev->priv = ax772_data;
+
+ ax772_data->ax_work = create_singlethread_workqueue ("ax88772");
+ if (!ax772_data->ax_work) {
+ kfree (ax772_data);
+ kfree (buf);
+ return -ENOMEM;
+ }
+
+ ax772_data->dev = dev;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ INIT_WORK (&ax772_data->check_link, ax88772_link_reset, dev);
+#else
+ INIT_WORK (&ax772_data->check_link, ax88772_link_reset);
+#endif
+
+ /* reload eeprom data */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+ 0x00B0, 0, 0, NULL)) < 0)
+ goto out2;
+
+ msleep(5);
+
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = ax8817x_mdio_read_le;
+ dev->mii.mdio_write = ax8817x_mdio_write_le;
+ dev->mii.phy_id_mask = 0xff;
+ dev->mii.reg_num_mask = 0xff;
+
+ /* Get the PHY id */
+ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID,
+ 0, 0, 2, buf)) < 0) {
+ deverr(dev, "Error reading PHY ID: %02x", ret);
+ goto out2;
+ } else if (ret < 2) {
+ /* this should always return 2 bytes */
+ deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x",
+ ret);
+ ret = -EIO;
+ goto out2;
+ }
+ dev->mii.phy_id = *((u8 *)buf + 1);
+
+ if (dev->mii.phy_id == 0x10)
+ {
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
+ 0x0001, 0, 0, NULL)) < 0) {
+ deverr(dev, "Select PHY #1 failed: %d", ret);
+ goto out2;
}
- asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
- AX_MCAST_FILTER_SIZE, data->multi_filter);
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD,
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to power down PHY: %d", ret);
+ goto out2;
+ }
+
+ msleep(150);
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_CLEAR,
+ 0, 0, NULL)) < 0) {
+ deverr(dev,
+ "Failed to perform software reset: %d", ret);
+ goto out2;
+ }
+
+ msleep(150);
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL | AX_SWRESET_PRL,
+ 0, 0, NULL)) < 0) {
+ deverr(dev,
+ "Failed to set PHY reset control: %d", ret);
+ goto out2;
+ }
+ }
+ else
+ {
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
+ 0x0000, 0, 0, NULL)) < 0) {
+ deverr(dev, "Select PHY #1 failed: %d", ret);
+ goto out2;
+ }
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD | AX_SWRESET_PRL,
+ 0, 0, NULL)) < 0) {
+ deverr(dev,
+ "Failed to power down internal PHY: %d", ret);
+ goto out2;
+ }
+ }
+
+ msleep(150);
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ 0x0000, 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to reset RX_CTL: %d", ret);
+ goto out2;
+ }
+
+ /* Get the MAC address */
+ memset(buf, 0, ETH_ALEN);
+ if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID,
+ 0, 0, ETH_ALEN, buf)) < 0) {
+ deverr(dev, "Failed to read MAC address: %d", ret);
+ goto out2;
+ }
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII,
+ 0, 0, 0, NULL)) < 0) {
+ deverr(dev, "Enabling software MII failed: %d", ret);
+ goto out2;
+ }
+
+ if (dev->mii.phy_id == 0x10)
+ {
+ if ((ret = ax8817x_mdio_read_le(dev->net,
+ dev->mii.phy_id, 2)) != 0x003b) {
+ deverr(dev, "Read PHY register 2 must be 0x3b00: %d",
+ ret);
+ goto out2;
+ }
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_PRL,
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "Set external PHY reset pin level: %d", ret);
+ goto out2;
+ }
+ msleep(150);
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL | AX_SWRESET_PRL,
+ 0, 0, NULL)) < 0) {
+ deverr(dev,
+ "Set Internal/External PHY reset control: %d",
+ ret);
+ goto out2;
+ }
+ msleep(150);
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ dev->net->do_ioctl = ax8817x_ioctl;
+ dev->net->set_multicast_list = ax8817x_set_multicast;
+ dev->net->set_mac_address = ax8817x_set_mac_addr;
+#else
+ dev->net->netdev_ops = &ax88x72_netdev_ops;
+#endif
+
+ dev->net->ethtool_ops = &ax88772_ethtool_ops;
+
+ /* Register suspend and resume functions */
+ data->suspend = ax88772_suspend;
+ data->resume = ax88772_resume;
+
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA);
- rx_ctl |= 0x10;
+ mii_nway_restart(&dev->mii);
+ ax772_data->autoneg_start = jiffies;
+ ax772_data->Event = WAIT_AUTONEG_COMPLETE;
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+ 0, 0, 0, NULL)) < 0) {
+ deverr(dev, "Write medium mode register: %d", ret);
+ goto out2;
+ }
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0,
+ AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT << 8,
+ AX88772_IPG2_DEFAULT, 0, NULL)) < 0) {
+ deverr(dev, "Write IPG,IPG1,IPG2 failed: %d", ret);
+ goto out2;
+ }
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to set hardware MII: %02x", ret);
+ goto out2;
+ }
+
+ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+ if ((ret =
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0,
+ NULL)) < 0) {
+ deverr(dev, "Reset RX_CTL failed: %d", ret);
+ goto out2;
+ }
+
+ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
+ if (dev->driver_info->flags & FLAG_FRAMING_AX) {
+ /* hard_mtu is still the default - the device does not support
+ jumbo eth frames */
+ dev->rx_urb_size = 2048;
}
- asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+ kfree (buf);
+ printk (version);
+ return 0;
+
+out2:
+ destroy_workqueue (ax772_data->ax_work);
+ kfree (ax772_data);
+ kfree(buf);
+out1:
+ return ret;
}
-static int ax88172_link_reset(struct usbnet *dev)
+static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
{
- u8 mode;
- struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv;
- mii_check_media(&dev->mii, 1, 1);
- mii_ethtool_gset(&dev->mii, &ecmd);
- mode = AX88172_MEDIUM_DEFAULT;
+ if (ax772_data) {
- if (ecmd.duplex != DUPLEX_FULL)
- mode |= ~AX88172_MEDIUM_FD;
+ flush_workqueue (ax772_data->ax_work);
+ destroy_workqueue (ax772_data->ax_work);
- netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
- ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
+ /* stop MAC operation */
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ AX_RX_CTL_STOP, 0, 0, NULL);
- asix_write_medium_mode(dev, mode);
+ /* Power down PHY */
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD, 0, 0, NULL);
- return 0;
+ kfree (ax772_data);
+ }
}
-static const struct net_device_ops ax88172_netdev_ops = {
- .ndo_open = usbnet_open,
- .ndo_stop = usbnet_stop,
- .ndo_start_xmit = usbnet_start_xmit,
- .ndo_tx_timeout = usbnet_tx_timeout,
- .ndo_change_mtu = usbnet_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_do_ioctl = asix_ioctl,
- .ndo_set_multicast_list = ax88172_set_multicast,
-};
+static int ax88772a_phy_powerup (struct usbnet *dev)
+{
+ int ret;
+ /* set the embedded Ethernet PHY in power-down state */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD | AX_SWRESET_IPRL, 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to power down PHY: %d", ret);
+ return ret;
+ }
+
+ msleep(10);
+
+
+ /* set the embedded Ethernet PHY in power-up state */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL, 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to reset PHY: %d", ret);
+ return ret;
+ }
+
+ msleep(600);
+
+ /* set the embedded Ethernet PHY in reset state */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_CLEAR, 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to power up PHY: %d", ret);
+ return ret;
+ }
+
+ /* set the embedded Ethernet PHY in power-up state */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL, 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to reset PHY: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
-static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
+static int ax88772a_bind(struct usbnet *dev, struct usb_interface *intf)
{
- int ret = 0;
- u8 buf[ETH_ALEN];
- int i;
- unsigned long gpio_bits = dev->driver_info->data;
- struct asix_data *data = (struct asix_data *)&dev->data;
+ int ret = -EIO;
+ void *buf;
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+ struct ax88772a_data *ax772a_data = NULL;
- data->eeprom_len = AX88172_EEPROM_LEN;
+ axusbnet_get_endpoints(dev,intf);
- usbnet_get_endpoints(dev,intf);
+ buf = kmalloc(6, GFP_KERNEL);
+ if(!buf) {
+ deverr(dev, "Cannot allocate memory for buffer");
+ ret = -ENOMEM;
+ goto out1;
+ }
- /* Toggle the GPIOs in a manufacturer/model specific way */
- for (i = 2; i >= 0; i--) {
- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,
- (gpio_bits >> (i * 8)) & 0xff, 0, 0,
- NULL)) < 0)
- goto out;
- msleep(5);
+ ax772a_data = kmalloc (sizeof(*ax772a_data), GFP_KERNEL);
+ if (!ax772a_data) {
+ deverr(dev, "Cannot allocate memory for AX88772A data");
+ kfree (buf);
+ return -ENOMEM;
+ }
+ memset (ax772a_data, 0, sizeof(*ax772a_data));
+ dev->priv = ax772a_data;
+
+ ax772a_data->ax_work = create_singlethread_workqueue ("ax88772a");
+ if (!ax772a_data->ax_work) {
+ kfree (ax772a_data);
+ kfree (buf);
+ return -ENOMEM;
+ }
+
+ ax772a_data->dev = dev;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ INIT_WORK (&ax772a_data->check_link, ax88772a_link_reset, dev);
+#else
+ INIT_WORK (&ax772a_data->check_link, ax88772a_link_reset);
+#endif
+
+ /* Get the EEPROM data*/
+ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM,
+ 0x0017, 0, 2, (void *)&ax772a_data->EepromData)) < 0) {
+ deverr(dev, "read SROM address 17h failed: %d", ret);
+ goto out2;
+ }
+ le16_to_cpus (&ax772a_data->EepromData);
+ /* End of get EEPROM data */
+
+ /* reload eeprom data */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+ AXGPIOS_RSE, 0, 0, NULL)) < 0)
+ goto out2;
+
+ msleep(5);
+
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = ax8817x_mdio_read_le;
+ dev->mii.mdio_write = ax8817x_mdio_write_le;
+ dev->mii.phy_id_mask = 0xff;
+ dev->mii.reg_num_mask = 0xff;
+
+ /* Get the PHY id */
+ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID,
+ 0, 0, 2, buf)) < 0) {
+ deverr(dev, "Error reading PHY ID: %02x", ret);
+ goto out2;
+ } else if (ret < 2) {
+ /* this should always return 2 bytes */
+ deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x",
+ ret);
+ goto out2;
+ }
+ dev->mii.phy_id = *((u8 *)buf + 1);
+
+ if(dev->mii.phy_id != 0x10) {
+ deverr(dev, "Got wrong PHY ID: %02x", dev->mii.phy_id);
+ goto out2;
+ }
+
+ /* select the embedded 10/100 Ethernet PHY */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
+ AX_PHYSEL_SSEN | AX_PHYSEL_PSEL | AX_PHYSEL_SSMII,
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "Select PHY #1 failed: %d", ret);
+ goto out2;
}
- if ((ret = asix_write_rx_ctl(dev, 0x80)) < 0)
- goto out;
+ if ((ret = ax88772a_phy_powerup (dev)) < 0)
+ goto out2;
+
+ /* stop MAC operation */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ AX_RX_CTL_STOP, 0, 0, NULL)) < 0) {
+ deverr(dev, "Reset RX_CTL failed: %d", ret);
+ goto out2;
+ }
/* Get the MAC address */
- if ((ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID,
+ memset(buf, 0, ETH_ALEN);
+ if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID,
0, 0, ETH_ALEN, buf)) < 0) {
- dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
- goto out;
+ deverr(dev, "Failed to read MAC address: %d", ret);
+ goto out2;
}
memcpy(dev->net->dev_addr, buf, ETH_ALEN);
- /* Initialize MII structure */
- dev->mii.dev = dev->net;
- dev->mii.mdio_read = asix_mdio_read;
- dev->mii.mdio_write = asix_mdio_write;
- dev->mii.phy_id_mask = 0x3f;
- dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = asix_get_phy_addr(dev);
+ /* make sure the driver can enable sw mii operation */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII,
+ 0, 0, 0, NULL)) < 0) {
+ deverr(dev, "Enabling software MII failed: %d", ret);
+ goto out2;
+ }
- dev->net->netdev_ops = &ax88172_netdev_ops;
- dev->net->ethtool_ops = &ax88172_ethtool_ops;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ dev->net->do_ioctl = ax8817x_ioctl;
+ dev->net->set_multicast_list = ax8817x_set_multicast;
+ dev->net->set_mac_address = ax8817x_set_mac_addr;
+#else
+ dev->net->netdev_ops = &ax88x72_netdev_ops;
+#endif
+
+ dev->net->ethtool_ops = &ax88772_ethtool_ops;
+
+ /* Register suspend and resume functions */
+ data->suspend = ax88772_suspend;
+ data->resume = ax88772_resume;
+
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
- ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
mii_nway_restart(&dev->mii);
+ ax772a_data->autoneg_start = jiffies;
+ ax772a_data->Event = WAIT_AUTONEG_COMPLETE;
- return 0;
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+ 0, 0, 0, NULL)) < 0) {
+ deverr(dev, "Write medium mode register: %d", ret);
+ goto out2;
+ }
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0,
+ AX88772A_IPG0_DEFAULT | AX88772A_IPG1_DEFAULT << 8,
+ AX88772A_IPG2_DEFAULT, 0, NULL)) < 0) {
+ deverr(dev, "Write IPG,IPG1,IPG2 failed: %d", ret);
+ goto out2;
+ }
+
+ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ (AX_RX_CTL_START | AX_RX_CTL_AB),
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "Reset RX_CTL failed: %d", ret);
+ goto out2;
+ }
+
+ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
+ if (dev->driver_info->flags & FLAG_FRAMING_AX) {
+ /* hard_mtu is still the default - the device does not support
+ jumbo eth frames */
+ dev->rx_urb_size = 2048;
+ }
+
+ kfree (buf);
-out:
+ printk (version);
+
+ return ret;
+out2:
+ destroy_workqueue (ax772a_data->ax_work);
+ kfree (ax772a_data);
+ kfree (buf);
+out1:
return ret;
}
-static const struct ethtool_ops ax88772_ethtool_ops = {
- .get_drvinfo = asix_get_drvinfo,
- .get_link = asix_get_link,
- .get_msglevel = usbnet_get_msglevel,
- .set_msglevel = usbnet_set_msglevel,
- .get_wol = asix_get_wol,
- .set_wol = asix_set_wol,
- .get_eeprom_len = asix_get_eeprom_len,
- .get_eeprom = asix_get_eeprom,
- .get_settings = usbnet_get_settings,
- .set_settings = usbnet_set_settings,
- .nway_reset = usbnet_nway_reset,
-};
-
-static int ax88772_link_reset(struct usbnet *dev)
+static void ax88772a_unbind(struct usbnet *dev, struct usb_interface *intf)
{
- u16 mode;
- struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv;
+
+ if (ax772a_data) {
+
+ flush_workqueue (ax772a_data->ax_work);
+ destroy_workqueue (ax772a_data->ax_work);
+
+ /* stop MAC operation */
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ AX_RX_CTL_STOP, 0, 0, NULL);
+
+ /* Power down PHY */
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD, 0, 0, NULL);
+
+ kfree (ax772a_data);
+ }
+}
- mii_check_media(&dev->mii, 1, 1);
- mii_ethtool_gset(&dev->mii, &ecmd);
- mode = AX88772_MEDIUM_DEFAULT;
+static int ax88772b_set_csums(struct usbnet *dev)
+{
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
+ u16 checksum;
- if (ethtool_cmd_speed(&ecmd) != SPEED_100)
- mode &= ~AX_MEDIUM_PS;
+ if (ax772b_data->checksum & AX_RX_CHECKSUM)
+ checksum = AX_RXCOE_DEF_CSUM;
+ else
+ checksum = 0;
- if (ecmd.duplex != DUPLEX_FULL)
- mode &= ~AX_MEDIUM_FD;
+ ax8817x_write_cmd (dev, AX_CMD_WRITE_RXCOE_CTL,
+ checksum, 0, 0, NULL);
- netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
- ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
+ if (ax772b_data->checksum & AX_TX_CHECKSUM)
+ checksum = AX_TXCOE_DEF_CSUM;
+ else
+ checksum = 0;
- asix_write_medium_mode(dev, mode);
+ ax8817x_write_cmd (dev, AX_CMD_WRITE_TXCOE_CTL,
+ checksum, 0, 0, NULL);
return 0;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
+static u32 ax88772b_get_tx_csum(struct net_device *netdev)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
-static const struct net_device_ops ax88772_netdev_ops = {
- .ndo_open = usbnet_open,
- .ndo_stop = usbnet_stop,
- .ndo_start_xmit = usbnet_start_xmit,
- .ndo_tx_timeout = usbnet_tx_timeout,
- .ndo_change_mtu = usbnet_change_mtu,
- .ndo_set_mac_address = asix_set_mac_address,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_do_ioctl = asix_ioctl,
- .ndo_set_multicast_list = asix_set_multicast,
-};
+ return (ax772b_data->checksum & AX_TX_CHECKSUM);
+}
-static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
+static u32 ax88772b_get_rx_csum(struct net_device *netdev)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
+
+ return (ax772b_data->checksum & AX_RX_CHECKSUM);
+}
+
+static int ax88772b_set_rx_csum(struct net_device *netdev, u32 val)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
+
+ if (val)
+ ax772b_data->checksum |= AX_RX_CHECKSUM;
+ else
+ ax772b_data->checksum &= ~AX_RX_CHECKSUM;
+
+ return ax88772b_set_csums(dev);
+}
+
+static int ax88772b_set_tx_csum(struct net_device *netdev, u32 val)
{
- int ret, embd_phy;
- u16 rx_ctl;
- struct asix_data *data = (struct asix_data *)&dev->data;
- u8 buf[ETH_ALEN];
- u32 phyid;
+ struct usbnet *dev = netdev_priv(netdev);
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
- data->eeprom_len = AX88772_EEPROM_LEN;
+ if (val)
+ ax772b_data->checksum |= AX_TX_CHECKSUM;
+ else
+ ax772b_data->checksum &= ~AX_TX_CHECKSUM;
+
+ ethtool_op_set_tx_csum(netdev, val);
+
+ return ax88772b_set_csums(dev);
+}
+#endif
+static struct ethtool_ops ax88772b_ethtool_ops = {
+ .get_drvinfo = ax8817x_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = axusbnet_get_msglevel,
+ .set_msglevel = axusbnet_set_msglevel,
+ .get_wol = ax8817x_get_wol,
+ .set_wol = ax8817x_set_wol,
+ .get_eeprom_len = ax8817x_get_eeprom_len,
+ .get_eeprom = ax8817x_get_eeprom,
+ .get_settings = ax8817x_get_settings,
+ .set_settings = ax8817x_set_settings,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
+ .set_tx_csum = ax88772b_set_tx_csum,
+ .get_tx_csum = ax88772b_get_tx_csum,
+ .get_rx_csum = ax88772b_get_rx_csum,
+ .set_rx_csum = ax88772b_set_rx_csum,
+#endif
+};
- usbnet_get_endpoints(dev,intf);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)
+static const struct net_device_ops ax88772b_netdev_ops = {
+ .ndo_open = axusbnet_open,
+ .ndo_stop = axusbnet_stop,
+ .ndo_start_xmit = axusbnet_start_xmit,
+ .ndo_tx_timeout = axusbnet_tx_timeout,
+ .ndo_change_mtu = axusbnet_change_mtu,
+ .ndo_do_ioctl = ax8817x_ioctl,
+ .ndo_get_stats = axusbnet_get_stats,
+ .ndo_set_mac_address = ax8817x_set_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,2,0)
+ .ndo_set_multicast_list = ax88772b_set_multicast,
+#else
+ .ndo_set_rx_mode = ax88772b_set_multicast,
+#endif
+};
+#endif
- if ((ret = asix_write_gpio(dev,
- AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0)
- goto out;
+static int ax88772b_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ int ret;
+ void *buf;
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+ struct ax88772b_data *ax772b_data;
+ u16 *tmp16;
+ u8 i;
+ u8 TempPhySelect;
+ bool InternalPhy;
+ u8 default_asix_mac[ETH_ALEN] = { 0x00, 0x0e, 0xc6, 0x87, 0x72, 0x01 };
+
+ axusbnet_get_endpoints(dev,intf);
+
+ buf = kmalloc (6, GFP_KERNEL);
+ if (!buf) {
+ deverr(dev, "Cannot allocate memory for buffer");
+ return -ENOMEM;
+ }
+ tmp16 = (u16 *)buf;
- /* 0x10 is the phy id of the embedded 10/100 ethernet phy */
- embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
- if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
- embd_phy, 0, 0, NULL)) < 0) {
- dbg("Select PHY #1 failed: %d", ret);
- goto out;
+ ax772b_data = kmalloc (sizeof(*ax772b_data), GFP_KERNEL);
+ if (!ax772b_data) {
+ deverr(dev, "Cannot allocate memory for AX88772B data");
+ kfree (buf);
+ return -ENOMEM;
+ }
+ memset (ax772b_data, 0, sizeof(*ax772b_data));
+ dev->priv = ax772b_data;
+
+ ax772b_data->ax_work = create_singlethread_workqueue ("ax88772b");
+ if (!ax772b_data->ax_work) {
+ kfree (buf);
+ kfree (ax772b_data);
+ return -ENOMEM;
}
- if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL)) < 0)
- goto out;
+ ax772b_data->dev = dev;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ INIT_WORK (&ax772b_data->check_link, ax88772b_link_reset, dev);
+#else
+ INIT_WORK (&ax772b_data->check_link, ax88772b_link_reset);
+#endif
+
+ if ((ret = ax8817x_read_cmd (dev, AX_CMD_SW_PHY_STATUS, 0, 0, 1,
+ &TempPhySelect)) < 0) {
+ deverr(dev, "read SW interface selection status register"
+ "failed: %d\n", ret);
+ goto err_out;
+ }
- msleep(150);
- if ((ret = asix_sw_reset(dev, AX_SWRESET_CLEAR)) < 0)
- goto out;
+ TempPhySelect &= 0x0C;
- msleep(150);
- if (embd_phy) {
- if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL)) < 0)
- goto out;
+ if (TempPhySelect == AX_PHYSEL_SSRMII) {
+ InternalPhy = false;
+ ax772b_data->OperationMode = OPERATION_MAC_MODE;
+ ax772b_data->PhySelect = 0x00;
+ }
+ else if (TempPhySelect == AX_PHYSEL_SSRRMII) {
+ InternalPhy = true;
+ ax772b_data->OperationMode = OPERATION_PHY_MODE;
+ ax772b_data->PhySelect = 0x00;
+ }
+ else if (TempPhySelect == AX_PHYSEL_SSMII) {
+ InternalPhy = true;
+ ax772b_data->OperationMode = OPERATION_MAC_MODE;
+ ax772b_data->PhySelect = 0x01;
}
else {
- if ((ret = asix_sw_reset(dev, AX_SWRESET_PRTE)) < 0)
- goto out;
+ deverr(dev, "Unknown MII type\n");
+ goto err_out;
}
- msleep(150);
- rx_ctl = asix_read_rx_ctl(dev);
- dbg("RX_CTL is 0x%04x after software reset", rx_ctl);
- if ((ret = asix_write_rx_ctl(dev, 0x0000)) < 0)
- goto out;
+ /* reload eeprom data */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
+ AXGPIOS_RSE, 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to enable GPIO finction: %d", ret);
+ goto err_out;
+ }
+ msleep(5);
- rx_ctl = asix_read_rx_ctl(dev);
- dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl);
+ /* Get the EEPROM data*/
+ if ((ret = ax8817x_read_cmd (dev, AX_CMD_READ_EEPROM,
+ 0x18, 0, 2, (void *)tmp16)) < 0) {
+ deverr(dev, "read SROM address 18h failed: %d", ret);
+ goto err_out;
+ }
+ le16_to_cpus(tmp16);
+ ax772b_data->psc = *tmp16 & 0xFF00;
+ /* End of get EEPROM data */
+
+ /* Get the MAC address from EEPROM */
+ memset(buf, 0, ETH_ALEN);
+ for (i = 0; i < (ETH_ALEN >> 1); i++) {
+ if ((ret = ax8817x_read_cmd (dev, AX_CMD_READ_EEPROM,
+ 0x04 + i, 0, 2, (buf + i * 2))) < 0) {
+ deverr(dev, "read SROM address 04h failed: %d", ret);
+ goto err_out;
+ }
+ }
- /* Get the MAC address */
- if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
- 0, 0, ETH_ALEN, buf)) < 0) {
- dbg("Failed to read MAC address: %d", ret);
- goto out;
+ /* Check for default ASIX MAC (e.g. 00:0e:c6:87:72:01) in case of no EEPROM being present */
+ if (!memcmp(buf, default_asix_mac, ETH_ALEN)) {
+ if (g_usr_mac && (g_usr_mac < 3)) {
+ /* Get user set MAC address */
+ if (g_usr_mac == 2) {
+ /* 0x100000 offset for 2nd Ethernet MAC */
+ g_mac_addr[3] += 0x10;
+ if (g_mac_addr[3] < 0x10)
+ devwarn(dev, "MAC address byte 3 (0x%02x) wrap around", g_mac_addr[3]);
+ }
+ memcpy(buf, g_mac_addr, ETH_ALEN);
+ g_usr_mac++;
+ } else devwarn(dev, "using default ASIX MAC");
}
memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+ /* Set the MAC address */
+ if ((ret = ax8817x_write_cmd (dev, AX88772_CMD_WRITE_NODE_ID,
+ 0, 0, ETH_ALEN, buf)) < 0) {
+ deverr(dev, "set MAC address failed: %d", ret);
+ goto err_out;
+ }
+
/* Initialize MII structure */
dev->mii.dev = dev->net;
- dev->mii.mdio_read = asix_mdio_read;
- dev->mii.mdio_write = asix_mdio_write;
- dev->mii.phy_id_mask = 0x1f;
- dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = asix_get_phy_addr(dev);
+ dev->mii.mdio_read = ax8817x_mdio_read_le;
+ dev->mii.mdio_write = ax88772b_mdio_write_le;
+ dev->mii.phy_id_mask = 0xff;
+ dev->mii.reg_num_mask = 0xff;
- phyid = asix_get_phyid(dev);
- dbg("PHYID=0x%08x", phyid);
+ /* Get the PHY id */
+ if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID,
+ 0, 0, 2, buf)) < 0) {
+ deverr(dev, "Error reading PHY ID: %02x", ret);
+ goto err_out;
+ } else if (ret < 2) {
+ /* this should always return 2 bytes */
+ deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x",
+ ret);
+ ret = -EIO;
+ goto err_out;
+ }
- if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0)
- goto out;
+ if (InternalPhy)
+ dev->mii.phy_id = *((u8 *)buf + 1);
+ else
+ dev->mii.phy_id = *((u8 *)buf);
- msleep(150);
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
+ ax772b_data->PhySelect, 0, 0, NULL)) < 0) {
+ deverr(dev, "Select PHY #1 failed: %d", ret);
+ goto err_out;
+ }
- if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0)
- goto out;
+#if 0
+ /* select the embedded 10/100 Ethernet PHY */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
+ AX_PHYSEL_SSEN | AX_PHYSEL_PSEL | AX_PHYSEL_SSMII
+ , 0, 0, NULL)) < 0) {
+ deverr(dev, "Select PHY #1 failed: %d", ret);
+ goto err_out;
+ }
- msleep(150);
+ if(dev->mii.phy_id != 0x10) {
+ deverr(dev, "Got wrong PHY ID: %02x", dev->mii.phy_id);
+ ret = -EIO;
+ goto err_out;
+ }
+#endif
+ if ((ret = ax88772a_phy_powerup (dev)) < 0)
+ goto err_out;
+
+ /* stop MAC operation */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ AX_RX_CTL_STOP, 0, 0, NULL)) < 0) {
+ deverr(dev, "Reset RX_CTL failed: %d", ret);
+ goto err_out;
+ }
- dev->net->netdev_ops = &ax88772_netdev_ops;
- dev->net->ethtool_ops = &ax88772_ethtool_ops;
+ /* make sure the driver can enable sw mii operation */
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII,
+ 0, 0, 0, NULL)) < 0) {
+ deverr(dev, "Enabling software MII failed: %d", ret);
+ goto err_out;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ dev->net->do_ioctl = ax8817x_ioctl;
+ dev->net->set_multicast_list = ax88772b_set_multicast;
+ dev->net->set_mac_address = ax8817x_set_mac_addr;
+#else
+ dev->net->netdev_ops = &ax88772b_netdev_ops;
+#endif
+
+ dev->net->ethtool_ops = &ax88772b_ethtool_ops;
+
+ /* Register suspend and resume functions */
+ data->suspend = ax88772b_suspend;
+ data->resume = ax88772b_resume;
+
+ if (ax772b_data->OperationMode == OPERATION_PHY_MODE)
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id
+ , MII_BMCR, 0x3900);
+
+ if (dev->mii.phy_id != 0x10)
+ ax8817x_mdio_write_le(dev->net, 0x10, MII_BMCR, 0x3900);
+
+
+ if (dev->mii.phy_id == 0x10 && ax772b_data->OperationMode
+ != OPERATION_PHY_MODE) {
+
+ *tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12);
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, 0x12,
+ ((*tmp16 & 0xFF9F) | 0x0040));
+ }
+
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
- ADVERTISE_ALL | ADVERTISE_CSMA);
mii_nway_restart(&dev->mii);
- if ((ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT)) < 0)
- goto out;
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+ 0, 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to write medium mode: %d", ret);
+ goto err_out;
+ }
- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
- AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
- AX88772_IPG2_DEFAULT, 0, NULL)) < 0) {
- dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
- goto out;
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0,
+ AX88772A_IPG0_DEFAULT | AX88772A_IPG1_DEFAULT << 8,
+ AX88772A_IPG2_DEFAULT, 0, NULL)) < 0) {
+ deverr(dev, "Failed to write interframe gap: %d", ret);
+ goto err_out;
}
- /* Set RX_CTL to default values with 2k buffer, and enable cactus */
- if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
- goto out;
+ dev->net->features |= NETIF_F_IP_CSUM;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)
+ dev->net->features |= NETIF_F_IPV6_CSUM;
+#endif
- rx_ctl = asix_read_rx_ctl(dev);
- dbg("RX_CTL is 0x%04x after all initializations", rx_ctl);
+ ax772b_data->checksum = AX_RX_CHECKSUM | AX_TX_CHECKSUM;
+ if ((ret = ax88772b_set_csums(dev)) < 0) {
+ deverr(dev, "Write RX_COE/TX_COE failed: %d", ret);
+ goto err_out;
+ }
- rx_ctl = asix_read_medium_status(dev);
- dbg("Medium Status is 0x%04x after all initializations", rx_ctl);
+ dev->rx_size = bsize & 0x07;
+ if (dev->udev->speed == USB_SPEED_HIGH) {
- /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
- if (dev->driver_info->flags & FLAG_FRAMING_AX) {
- /* hard_mtu is still the default - the device does not support
- jumbo eth frames */
+ if ((ret = ax8817x_write_cmd (dev, 0x2A,
+ AX88772B_BULKIN_SIZE[dev->rx_size].byte_cnt,
+ AX88772B_BULKIN_SIZE[dev->rx_size].threshold,
+ 0, NULL)) < 0) {
+ deverr(dev, "Reset RX_CTL failed: %d", ret);
+ goto err_out;
+ }
+
+ dev->rx_urb_size = AX88772B_BULKIN_SIZE[dev->rx_size].size;
+ } else {
+ if ((ret = ax8817x_write_cmd (dev, 0x2A,
+ 0x8000, 0x8001, 0, NULL)) < 0) {
+ deverr(dev, "Reset RX_CTL failed: %d", ret);
+ goto err_out;
+ }
dev->rx_urb_size = 2048;
}
- return 0;
-out:
+ /* Configure RX header type */
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_RX_CTL,
+ (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_HEADER_DEFAULT),
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "Reset RX_CTL failed: %d", ret);
+ goto err_out;
+ }
+
+ /* Overwrite power saving configuration from eeprom */
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL | (ax772b_data->psc & 0x7FFF), 0, 0, NULL)) < 0) {
+ deverr(dev, "Failed to configure PHY power saving: %d", ret);
+ goto err_out;
+ }
+
+ if (ax772b_data->OperationMode == OPERATION_PHY_MODE)
+ netif_carrier_on(dev->net);
+
+ kfree (buf);
+ printk (version);
+
+ return ret;
+err_out:
+ destroy_workqueue (ax772b_data->ax_work);
+ kfree (buf);
+ kfree (ax772b_data);
return ret;
}
-static struct ethtool_ops ax88178_ethtool_ops = {
- .get_drvinfo = asix_get_drvinfo,
- .get_link = asix_get_link,
- .get_msglevel = usbnet_get_msglevel,
- .set_msglevel = usbnet_set_msglevel,
- .get_wol = asix_get_wol,
- .set_wol = asix_set_wol,
- .get_eeprom_len = asix_get_eeprom_len,
- .get_eeprom = asix_get_eeprom,
- .get_settings = usbnet_get_settings,
- .set_settings = usbnet_set_settings,
- .nway_reset = usbnet_nway_reset,
-};
+static void ax88772b_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
+
+ if (ax772b_data) {
+ /* Check for user set MAC address */
+ if (!memcmp(dev->net->dev_addr, g_mac_addr, ETH_ALEN)) {
+ /* Release user set MAC address */
+ g_usr_mac--;
+
+ if (g_usr_mac == 2) {
+ /* 0x100000 offset for 2nd Ethernet MAC */
+ g_mac_addr[3] -= 0x10;
+ if (g_mac_addr[3] > 0xf0)
+ devwarn(dev, "MAC address byte 3 (0x%02x) wrap around", g_mac_addr[3]);
+ }
+ }
+
+ flush_workqueue (ax772b_data->ax_work);
+ destroy_workqueue (ax772b_data->ax_work);
+
+ /* stop MAC operation */
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ AX_RX_CTL_STOP, 0, 0, NULL);
+
+ /* Power down PHY */
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD, 0, 0, NULL);
+
+ kfree (ax772b_data);
+ }
+}
-static int marvell_phy_init(struct usbnet *dev)
+static int
+ax88178_media_check (struct usbnet *dev, struct ax88178_data *ax178dataptr)
{
- struct asix_data *data = (struct asix_data *)&dev->data;
- u16 reg;
+ int fullduplex;
+ u16 tempshort = 0;
+ u16 media;
+ u16 advertise, lpa, result, stat1000;
+
+ advertise = ax8817x_mdio_read_le (dev->net,
+ dev->mii.phy_id, MII_ADVERTISE);
+ lpa = ax8817x_mdio_read_le (dev->net, dev->mii.phy_id, MII_LPA);
+ result = advertise & lpa;
+
+ stat1000 = ax8817x_mdio_read_le (dev->net,
+ dev->mii.phy_id, MII_STAT1000);
+
+ if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) &&
+ (ax178dataptr->LedMode == 1)) {
+ tempshort = ax8817x_mdio_read_le (dev->net,
+ dev->mii.phy_id, MARVELL_MANUAL_LED) & 0xfc0f;
+ }
- netdev_dbg(dev->net, "marvell_phy_init()\n");
+ fullduplex=1;
+ if (stat1000 & LPA_1000FULL) {
+ media = MEDIUM_GIGA_MODE | MEDIUM_FULL_DUPLEX_MODE |
+ MEDIUM_ENABLE_125MHZ | MEDIUM_ENABLE_RECEIVE;
+ if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) &&
+ (ax178dataptr->LedMode == 1))
+ tempshort|= 0x3e0;
+ } else if (result & LPA_100FULL) {
+ media = MEDIUM_FULL_DUPLEX_MODE | MEDIUM_ENABLE_RECEIVE |
+ MEDIUM_MII_100M_MODE;
+ if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) &&
+ (ax178dataptr->LedMode == 1))
+ tempshort|= 0x3b0;
+ } else if (result & LPA_100HALF) {
+ fullduplex = 0;
+ media = MEDIUM_ENABLE_RECEIVE | MEDIUM_MII_100M_MODE;
+ if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) &&
+ (ax178dataptr->LedMode == 1))
+ tempshort |= 0x3b0;
+ } else if (result & LPA_10FULL) {
+ media = MEDIUM_FULL_DUPLEX_MODE | MEDIUM_ENABLE_RECEIVE;
+ if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) &&
+ (ax178dataptr->LedMode == 1))
+ tempshort |= 0x2f0;
+ } else {
+ media = MEDIUM_ENABLE_RECEIVE;
+ fullduplex=0;
+ if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) &&
+ (ax178dataptr->LedMode == 1))
+ tempshort |= 0x02f0;
+ }
- reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS);
- netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg);
+ if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) &&
+ (ax178dataptr->LedMode == 1)) {
+ ax8817x_mdio_write_le (dev->net,
+ dev->mii.phy_id, MARVELL_MANUAL_LED, tempshort);
+ }
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL,
- MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY);
+ media |= 0x0004;
+ if(ax178dataptr->UseRgmii)
+ media |= 0x0008;
+ if(fullduplex) {
+ media |= 0x0020; //ebable tx flow control as default;
+ media |= 0x0010; //ebable rx flow control as default;
+ }
- if (data->ledmode) {
- reg = asix_mdio_read(dev->net, dev->mii.phy_id,
- MII_MARVELL_LED_CTRL);
- netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg);
+ return media;
+}
- reg &= 0xf8ff;
- reg |= (1 + 0x0100);
- asix_mdio_write(dev->net, dev->mii.phy_id,
- MII_MARVELL_LED_CTRL, reg);
+static void Vitess_8601_Init (struct usbnet *dev, int State)
+{
+ u16 reg;
- reg = asix_mdio_read(dev->net, dev->mii.phy_id,
- MII_MARVELL_LED_CTRL);
- netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg);
- reg &= 0xfc0f;
+ switch (State) {
+ case 0: // tx, rx clock skew
+ ax8817x_swmii_mdio_write_le (dev->net, dev->mii.phy_id, 31, 1);
+ ax8817x_swmii_mdio_write_le (dev->net, dev->mii.phy_id, 28, 0);
+ ax8817x_swmii_mdio_write_le (dev->net, dev->mii.phy_id, 31, 0);
+ break;
+
+ case 1:
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 31, 0x52B5);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18, 0x009E);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, 0xDD39);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x87AA);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0xA7B4);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18,
+ ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 18));
+
+ reg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 17) & ~0x003f) | 0x003c;
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, reg);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x87B4);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0xa794);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18,
+ ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 18));
+
+ reg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 17) & ~0x003f) | 0x003e;
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, reg);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x8794);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18, 0x00f7);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, 0xbe36);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x879e);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0xa7a0);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18,
+ ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 18));
+
+ reg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 17) & ~0x003f) | 0x0034;
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, reg);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x87a0);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18, 0x003c);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, 0xf3cf);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x87a2);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18, 0x003c);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, 0xf3cf);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x87a4);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18, 0x003c);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, 0xd287);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x87a6);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0xa7a8);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18,
+ ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 18));
+
+ reg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 17) & ~0x0fff) | 0x0125;
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, reg);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x87a8);
+
+ // Enable Smart Pre-emphasis
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0xa7fa);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18,
+ ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 18));
+
+ reg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 17) & ~0x0008) | 0x0008;
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, reg);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x87fa);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 31, 0);
+
+ break;
}
+}
- return 0;
+static void
+marvell_88E1510_magic_init(struct usbnet *dev)
+{
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 22, 0xff);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, 0x214b);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x2144);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, 0x0c28);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x2146);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, 0xb233);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x214d);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, 0xcc0c);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x2159);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 22, 0x00fb);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 7, 0xc00d);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 22, 0);
}
-static int marvell_led_status(struct usbnet *dev, u16 speed)
+static int
+ax88178_phy_init (struct usbnet *dev, struct ax88178_data *ax178dataptr)
{
- u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL);
+ int i;
+ u16 PhyAnar, PhyAuxCtrl, PhyCtrl, TempShort, PhyID1;
+ u16 PhyReg = 0;
- netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg);
+ //Disable MII operation of AX88178 Hardware
+ ax8817x_write_cmd (dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
- /* Clear out the center LED bits - 0x03F0 */
- reg &= 0xfc0f;
- switch (speed) {
- case SPEED_1000:
- reg |= 0x03e0;
- break;
- case SPEED_100:
- reg |= 0x03b0;
- break;
- default:
- reg |= 0x02f0;
+ //Read SROM - MiiPhy Address (ID)
+ ax8817x_read_cmd (dev, AX_CMD_READ_PHY_ID, 0, 0, 2, &dev->mii.phy_id);
+ le32_to_cpus (&dev->mii.phy_id);
+
+ /* Initialize MII structure */
+ dev->mii.phy_id >>= 8;
+ dev->mii.phy_id &= PHY_ID_MASK;
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = ax8817x_mdio_read_le;
+ dev->mii.mdio_write = ax8817x_mdio_write_le;
+ dev->mii.phy_id_mask = 0x3f;
+ dev->mii.reg_num_mask = 0x1f;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11)
+ dev->mii.supports_gmii = 1;
+#endif
+
+ if (ax178dataptr->PhyMode == PHY_MODE_MAC_TO_MAC_GMII)
+ {
+ ax178dataptr->UseRgmii = 0;
+ ax178dataptr->MediaLink = MEDIUM_GIGA_MODE |
+ MEDIUM_FULL_DUPLEX_MODE |
+ MEDIUM_ENABLE_125MHZ |
+ MEDIUM_ENABLE_RECEIVE |
+ MEDIUM_ENABLE_RX_FLOWCTRL |
+ MEDIUM_ENABLE_TX_FLOWCTRL;
+
+ goto SkipPhySetting;
}
- netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg);
- asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg);
+ // test read phy register 2
+ if (!ax178dataptr->UseGpio0) {
+ i = 1000;
+ while (i--) {
+ PhyID1 = ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, GMII_PHY_OUI);
+ if ((PhyID1 == 0x000f) || (PhyID1 == 0x0141) ||
+ (PhyID1 == 0x0282) || (PhyID1 == 0x004d) ||
+ (PhyID1 == 0x0243) || (PhyID1 == 0x001C) ||
+ (PhyID1 == 0x0007))
+ break;
+ msleep(5);
+ }
+ if (i < 0)
+ return -EIO;
+ }
- return 0;
-}
+ ax178dataptr->UseRgmii = 0;
+ if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) {
+ PhyReg = ax8817x_swmii_mdio_read_le(dev->net,
+ dev->mii.phy_id, 27);
+ if (!(PhyReg & 4) && !(ax178dataptr->LedMode & 0x10)) {
+ ax178dataptr->UseRgmii = 1;
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 20, 0x82);
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+ } else if (ax178dataptr->LedMode & 0x10) {
+
+ ax178dataptr->UseRgmii = 1;
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+ marvell_88E1510_magic_init(dev);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 22, 2);
+
+ PhyReg = ax8817x_swmii_mdio_read_le(dev->net,
+ dev->mii.phy_id, 21);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 21, PhyReg | 0x30);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 22, 0);
+
+ }
+ } else if ((ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) ||
+ (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0_GMII)) {
+ if (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) {
+ ax178dataptr->UseRgmii = 1;
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+ }
+ } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V1) {
+ // not Cameo
+ if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) {
+ ax178dataptr->UseRgmii = 1;
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+ }
-static int ax88178_link_reset(struct usbnet *dev)
-{
- u16 mode;
- struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
- struct asix_data *data = (struct asix_data *)&dev->data;
- u32 speed;
+ for (i = 0; i < (sizeof(CICADA_FAMILY_HWINIT) /
+ sizeof(CICADA_FAMILY_HWINIT[0])); i++) {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id,
+ CICADA_FAMILY_HWINIT[i].offset,
+ CICADA_FAMILY_HWINIT[i].value);
+ }
- netdev_dbg(dev->net, "ax88178_link_reset()\n");
+ } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2) {
+ // not Cameo
+ if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode)
+ {
+ ax178dataptr->UseRgmii = 1;
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+ }
- mii_check_media(&dev->mii, 1, 1);
- mii_ethtool_gset(&dev->mii, &ecmd);
- mode = AX88178_MEDIUM_DEFAULT;
- speed = ethtool_cmd_speed(&ecmd);
+ for (i = 0; i < (sizeof(CICADA_V2_HWINIT) /
+ sizeof(CICADA_V2_HWINIT[0])); i++) {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, CICADA_V2_HWINIT[i].offset,
+ CICADA_V2_HWINIT[i].value);
+ }
+ } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2_ASIX) {
+ // not Cameo
+ if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode)
+ {
+ ax178dataptr->UseRgmii = 1;
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+ }
- if (speed == SPEED_1000)
- mode |= AX_MEDIUM_GM;
- else if (speed == SPEED_100)
- mode |= AX_MEDIUM_PS;
- else
- mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
+ for (i = 0; i < (sizeof(CICADA_V2_HWINIT) /
+ sizeof(CICADA_V2_HWINIT[0])); i++) {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, CICADA_V2_HWINIT[i].offset,
+ CICADA_V2_HWINIT[i].value);
+ }
+ } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211CL) {
+ ax178dataptr->UseRgmii = 1;
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+ } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211BN) {
+ ax178dataptr->UseRgmii = 1;
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+ } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8251CL) {
+ ax178dataptr->UseRgmii = 1;
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+ } else if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) {
+ ax178dataptr->UseRgmii = 1;
+ ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ;
+// Vitess_8601_Init (dev, 0);
+ }
- mode |= AX_MEDIUM_ENCK;
+ if (ax178dataptr->PhyMode != PHY_MODE_ATTANSIC_V0) {
+ // software reset
+ ax8817x_swmii_mdio_write_le (
+ dev->net, dev->mii.phy_id, GMII_PHY_CONTROL,
+ ax8817x_swmii_mdio_read_le (
+ dev->net, dev->mii.phy_id, GMII_PHY_CONTROL)
+ | GMII_CONTROL_RESET);
+ msleep (1);
+ }
- if (ecmd.duplex == DUPLEX_FULL)
- mode |= AX_MEDIUM_FD;
- else
- mode &= ~AX_MEDIUM_FD;
+ if ((ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) ||
+ (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0_GMII)) {
+ if (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0)
+ {
+ i = 1000;
+ while (i--)
+ {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 21, 0x1001);
+
+ PhyReg = ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 21);
+ if ((PhyReg & 0xf00f) == 0x1001)
+ break;
+ }
+ if (i < 0)
+ return -EIO;
+ }
+
+ if (ax178dataptr->LedMode == 4) {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 28, 0x7417);
+ } else if (ax178dataptr->LedMode == 9) {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 28, 0x7a10);
+ } else if (ax178dataptr->LedMode == 10) {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 28, 0x7a13);
+ }
+
+ for (i = 0; i < (sizeof(AGERE_FAMILY_HWINIT) /
+ sizeof(AGERE_FAMILY_HWINIT[0])); i++) {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, AGERE_FAMILY_HWINIT[i].offset,
+ AGERE_FAMILY_HWINIT[i].value);
+ }
+ } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211CL) {
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 0x1f, 0x0005);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 0x0c, 0);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 0x01,
+ (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 0x01) | 0x0080));
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 0x1f, 0);
+
+ if (ax178dataptr->LedMode == 12) {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 0x1f, 0x0002);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 0x1a, 0x00cb);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 0x1f, 0);
+ }
+ } else if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) {
+ Vitess_8601_Init (dev, 1);
+ }
+
+ // read phy register 0
+ PhyCtrl = ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, GMII_PHY_CONTROL);
+ TempShort = PhyCtrl;
+ PhyCtrl &= ~(GMII_CONTROL_POWER_DOWN | GMII_CONTROL_ISOLATE);
+ if (PhyCtrl != TempShort) {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, GMII_PHY_CONTROL, PhyCtrl);
+ }
+
+ // led
+ if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) {
+ if (ax178dataptr->LedMode == 1) {
+
+ PhyReg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 24) & 0xf8ff) | (1 + 0x100);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 24, PhyReg);
+ PhyReg = ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 25) & 0xfc0f;
+
+ } else if (ax178dataptr->LedMode == 2) {
+
+ PhyReg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 24) & 0xf886) |
+ (1 + 0x10 + 0x300);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 24, PhyReg);
+
+ } else if (ax178dataptr->LedMode == 5) {
+
+ PhyReg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 24) & 0xf8be) |
+ (1 + 0x40 + 0x300);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 24, PhyReg);
+
+ } else if (ax178dataptr->LedMode == 7) {
+
+ PhyReg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 24) & 0xf8ff) |
+ (1 + 0x100);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 24, PhyReg);
+
+ } else if (ax178dataptr->LedMode == 8) {
+
+ PhyReg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 24) & 0xf8be) |
+ (1 + 0x40 + 0x100);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 24, PhyReg);
+
+ } else if (ax178dataptr->LedMode == 11) {
+
+ PhyReg = ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 24) & 0x4106;
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 24, PhyReg);
+
+ } else if (ax178dataptr->LedMode == 0x10) {
+ //MARVEL 88e1510 use default led setting
+ }
+
+ } else if ((ax178dataptr->PhyMode == PHY_MODE_CICADA_V1) ||
+ (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2) ||
+ (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2_ASIX)) {
+
+ if (ax178dataptr->LedMode == 3) {
+
+ PhyReg = (ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 27) & 0xFCFF) | 0x0100;
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 27, PhyReg);
+ }
+
+ }
+
+ if (ax178dataptr->PhyMode == PHY_MODE_MARVELL)
+ {
+ if (ax178dataptr->LedMode == 1)
+ PhyReg |= 0x3f0;
+ }
+
+ PhyAnar = 1 | (GMII_ANAR_PAUSE | GMII_ANAR_100TXFD | GMII_ANAR_100TX |
+ GMII_ANAR_10TFD | GMII_ANAR_10T | GMII_ANAR_ASYM_PAUSE);
+
+ PhyAuxCtrl = GMII_1000_AUX_CTRL_FD_CAPABLE;
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, GMII_PHY_ANAR, PhyAnar);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, GMII_PHY_1000BT_CONTROL, PhyAuxCtrl);
+
+ if (ax178dataptr->PhyMode == PHY_MODE_VSC8601)
+ {
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 31, 0x52B5);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0xA7F8);
+
+ TempShort = ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 17) & (~0x0018);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 17, TempShort);
+
+ TempShort = ax8817x_swmii_mdio_read_le (dev->net,
+ dev->mii.phy_id, 18);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 18, TempShort);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 16, 0x87F8);
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 31, 0);
+ }
+
+ if (ax178dataptr->PhyMode == PHY_MODE_ATTANSIC_V0) {
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, GMII_PHY_CONTROL, 0x9000);
+
+ } else {
+ PhyCtrl &= ~GMII_CONTROL_LOOPBACK;
+ PhyCtrl |= (GMII_CONTROL_ENABLE_AUTO | GMII_CONTROL_START_AUTO);
+
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, GMII_PHY_CONTROL, PhyCtrl);
+ }
+
+ if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) {
+ if (ax178dataptr->LedMode == 1)
+ ax8817x_swmii_mdio_write_le (dev->net,
+ dev->mii.phy_id, 25, PhyReg);
+ }
- netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
- speed, ecmd.duplex, mode);
+SkipPhySetting:
- asix_write_medium_mode(dev, mode);
+ ax8817x_write_cmd (dev, AX_CMD_WRITE_MEDIUM_MODE,
+ ax178dataptr->MediaLink, 0, 0, NULL);
- if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
- marvell_led_status(dev, speed);
+ ax8817x_write_cmd (dev, AX_CMD_WRITE_IPG0,
+ AX88772_IPG0_DEFAULT | (AX88772_IPG1_DEFAULT << 8),
+ AX88772_IPG2_DEFAULT, 0, NULL);
+
+ msleep (1);
+
+ ax8817x_write_cmd (dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL);
return 0;
}
-static void ax88178_set_mfb(struct usbnet *dev)
+static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
{
- u16 mfb = AX_RX_CTL_MFB_16384;
- u16 rxctl;
- u16 medium;
- int old_rx_urb_size = dev->rx_urb_size;
+ int ret;
+ void *buf;
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+ struct ax88178_data *ax178dataptr = NULL;
- if (dev->hard_mtu < 2048) {
- dev->rx_urb_size = 2048;
- mfb = AX_RX_CTL_MFB_2048;
- } else if (dev->hard_mtu < 4096) {
- dev->rx_urb_size = 4096;
- mfb = AX_RX_CTL_MFB_4096;
- } else if (dev->hard_mtu < 8192) {
- dev->rx_urb_size = 8192;
- mfb = AX_RX_CTL_MFB_8192;
- } else if (dev->hard_mtu < 16384) {
+ axusbnet_get_endpoints(dev,intf);
+
+ buf = kmalloc(6, GFP_KERNEL);
+ if(!buf) {
+ deverr(dev, "Cannot allocate memory for buffer");
+ return -ENOMEM;
+ }
+
+ /* allocate 178 data */
+ ax178dataptr = kmalloc (sizeof (*ax178dataptr), GFP_KERNEL);
+ if (!ax178dataptr) {
+ deverr(dev, "Cannot allocate memory for AX88178 data");
+ ret = -ENOMEM;
+ goto error_out;
+ }
+ memset (ax178dataptr, 0, sizeof (struct ax88178_data));
+ dev->priv = ax178dataptr;
+ /* end of allocate 178 data */
+
+ /* Get the EEPROM data*/
+ if ((ret = ax8817x_read_cmd (dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2,
+ (void *)(&ax178dataptr->EepromData))) < 0) {
+ deverr(dev, "read SROM address 17h failed: %d", ret);
+ goto error_out;
+ }
+ le16_to_cpus (&ax178dataptr->EepromData);
+ /* End of get EEPROM data */
+
+ if (ax178dataptr->EepromData == 0xffff) {
+ ax178dataptr->PhyMode = PHY_MODE_MARVELL;
+ ax178dataptr->LedMode = 0;
+ ax178dataptr->UseGpio0 = 1; //True
+ } else {
+ ax178dataptr->PhyMode = (u8)(ax178dataptr->EepromData &
+ EEPROMMASK);
+ ax178dataptr->LedMode = (u8)(ax178dataptr->EepromData >> 8);
+ if (ax178dataptr->LedMode == 6) // for buffalo new (use gpio2)
+ ax178dataptr->LedMode = 1;
+ else if (ax178dataptr->LedMode == 1)
+ ax178dataptr->BuffaloOld = 1;
+
+
+ if(ax178dataptr->EepromData & 0x80) {
+ ax178dataptr->UseGpio0=0; //MARVEL se and other
+ } else {
+ ax178dataptr->UseGpio0=1; //cameo
+ }
+ }
+
+ if (ax178dataptr->UseGpio0) {
+
+ if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) {
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ AXGPIOS_GPO0EN | AXGPIOS_RSE,
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ msleep (25);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_GPO2 | AXGPIOS_GPO2EN |
+ AXGPIOS_GPO0EN), 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ msleep (15);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ AXGPIOS_GPO2EN | AXGPIOS_GPO0EN,
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ msleep (245);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_GPO2 | AXGPIOS_GPO2EN |
+ AXGPIOS_GPO0EN), 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ } else { // vitesse
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_RSE | AXGPIOS_GPO0EN |
+ AXGPIOS_GPO0), 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ msleep (25);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_GPO0EN | AXGPIOS_GPO0 |
+ AXGPIOS_GPO2EN | AXGPIOS_GPO2),
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ msleep (25);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_GPO0EN | AXGPIOS_GPO0 |
+ AXGPIOS_GPO2EN), 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ msleep (245);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_GPO0EN | AXGPIOS_GPO0 |
+ AXGPIOS_GPO2EN | AXGPIOS_GPO2),
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+ }
+ } else { // use gpio1
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_GPO1 |AXGPIOS_GPO1EN | AXGPIOS_RSE),
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ if (ax178dataptr->BuffaloOld) {
+
+ msleep (350);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ AXGPIOS_GPO1EN, 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ msleep (350);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ AXGPIOS_GPO1EN | AXGPIOS_GPO1,
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+ }
+ else
+ {
+ msleep (25);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_GPO1EN | AXGPIOS_GPO1 |
+ AXGPIOS_GPO2EN | AXGPIOS_GPO2),
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ msleep (25);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_GPO1EN | AXGPIOS_GPO1 |
+ AXGPIOS_GPO2EN), 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+
+ msleep (245);
+
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_WRITE_GPIOS,
+ (AXGPIOS_GPO1EN | AXGPIOS_GPO1 |
+ AXGPIOS_GPO2EN | AXGPIOS_GPO2),
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "write GPIO failed: %d", ret);
+ goto error_out;
+ }
+ }
+ }
+
+ if ((ret = ax8817x_write_cmd(dev,
+ AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL)) < 0) {
+ deverr(dev, "Select PHY failed: %d", ret);
+ goto error_out;
+ }
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD | AX_SWRESET_PRL, 0, 0, NULL)) < 0) {
+ deverr(dev, "Issue sw reset failed: %d", ret);
+ goto error_out;
+ }
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ 0, 0, 0, NULL)) < 0) {
+ deverr(dev, "Issue rx ctrl failed: %d", ret);
+ goto error_out;
+ }
+
+ /* Get the MAC address */
+ memset(buf, 0, ETH_ALEN);
+ if ((ret = ax8817x_read_cmd (dev, AX88772_CMD_READ_NODE_ID,
+ 0, 0, ETH_ALEN, buf)) < 0) {
+ deverr(dev, "read AX_CMD_READ_NODE_ID failed: %d", ret);
+ goto error_out;
+ }
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
+ /* End of get MAC address */
+
+ if ((ret = ax88178_phy_init (dev, ax178dataptr)) < 0)
+ goto error_out;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ dev->net->do_ioctl = ax8817x_ioctl;
+ dev->net->set_multicast_list = ax88178_set_multicast;
+ dev->net->set_mac_address = ax88178_set_mac_addr;
+#else
+ dev->net->netdev_ops = &ax88178_netdev_ops;
+#endif
+ dev->net->ethtool_ops = &ax8817x_ethtool_ops;
+
+ /* Register suspend and resume functions */
+ data->suspend = ax88772_suspend;
+ data->resume = ax88772_resume;
+
+ if (dev->driver_info->flags & FLAG_FRAMING_AX) {
dev->rx_urb_size = 16384;
- mfb = AX_RX_CTL_MFB_16384;
}
- rxctl = asix_read_rx_ctl(dev);
- asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb);
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ (AX_RX_CTL_MFB | AX_RX_CTL_START | AX_RX_CTL_AB),
+ 0, 0, NULL)) < 0) {
+ deverr(dev, "write RX ctrl reg failed: %d", ret);
+ goto error_out;
+ }
- medium = asix_read_medium_status(dev);
- if (dev->net->mtu > 1500)
- medium |= AX_MEDIUM_JFE;
- else
- medium &= ~AX_MEDIUM_JFE;
- asix_write_medium_mode(dev, medium);
+ kfree (buf);
+ printk (version);
+ return ret;
- if (dev->rx_urb_size > old_rx_urb_size)
- usbnet_unlink_rx_urbs(dev);
+error_out:
+ if (ax178dataptr)
+ kfree (ax178dataptr);
+ kfree (buf);
+ return ret;
}
-static int ax88178_change_mtu(struct net_device *net, int new_mtu)
+static void ax88178_unbind(struct usbnet *dev, struct usb_interface *intf)
{
- struct usbnet *dev = netdev_priv(net);
- int ll_mtu = new_mtu + net->hard_header_len + 4;
+ struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv;
- netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu);
+ if (ax178dataptr) {
- if (new_mtu <= 0 || ll_mtu > 16384)
- return -EINVAL;
+ /* stop MAC operation */
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL,
+ AX_RX_CTL_STOP, 0, 0, NULL);
+
+ kfree (ax178dataptr);
+ }
+}
+
+static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ u8 *head;
+ u32 header;
+ char *packet;
+ struct sk_buff *ax_skb;
+ u16 size;
+
+ head = (u8 *) skb->data;
+ memcpy(&header, head, sizeof(header));
+ le32_to_cpus(&header);
+ packet = head + sizeof(header);
- if ((ll_mtu % dev->maxpacket) == 0)
- return -EDOM;
+ skb_pull(skb, 4);
- net->mtu = new_mtu;
- dev->hard_mtu = net->mtu + net->hard_header_len;
- ax88178_set_mfb(dev);
+ while (skb->len > 0) {
+ if ((short)(header & 0x0000ffff) !=
+ ~((short)((header & 0xffff0000) >> 16))) {
+ deverr(dev, "header length data is error 0x%08x, %d\n",
+ header, skb->len);
+ }
+ /* get the packet length */
+ size = (u16) (header & 0x0000ffff);
- return 0;
+ if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
+
+ /* Make sure ip header is aligned on 32-bit boundary */
+ if (!((unsigned long)skb->data & 0x02)) {
+ memmove (skb->data - 2, skb->data, size);
+ skb->data -= 2;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ skb->tail = skb->data + size;
+#else
+ skb_set_tail_pointer (skb, size);
+#endif
+ }
+ skb->truesize = size + sizeof(struct sk_buff);
+ return 2;
+ }
+
+ if (size > ETH_FRAME_LEN) {
+ deverr(dev, "invalid rx length %d", size);
+ return 0;
+ }
+ ax_skb = skb_clone(skb, GFP_ATOMIC);
+ if (ax_skb) {
+
+ /* Make sure ip header is aligned on 32-bit boundary */
+ if (!((unsigned long)packet & 0x02)) {
+ memmove (packet - 2, packet, size);
+ packet -= 2;
+ }
+ ax_skb->data = packet;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ ax_skb->tail = packet + size;
+#else
+ skb_set_tail_pointer (ax_skb, size);
+#endif
+ ax_skb->truesize = size + sizeof(struct sk_buff);
+ axusbnet_skb_return(dev, ax_skb);
+
+ } else {
+ return 0;
+ }
+
+ skb_pull(skb, (size + 1) & 0xfffe);
+
+ if (skb->len == 0)
+ break;
+
+ head = (u8 *) skb->data;
+ memcpy(&header, head, sizeof(header));
+ le32_to_cpus(&header);
+ packet = head + sizeof(header);
+ skb_pull(skb, 4);
+ }
+
+ if (skb->len < 0) {
+ deverr(dev, "invalid rx length %d", skb->len);
+ return 0;
+ }
+ return 1;
}
-static const struct net_device_ops ax88178_netdev_ops = {
- .ndo_open = usbnet_open,
- .ndo_stop = usbnet_stop,
- .ndo_start_xmit = usbnet_start_xmit,
- .ndo_tx_timeout = usbnet_tx_timeout,
- .ndo_set_mac_address = asix_set_mac_address,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_multicast_list = asix_set_multicast,
- .ndo_do_ioctl = asix_ioctl,
- .ndo_change_mtu = ax88178_change_mtu,
-};
+static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+ int padlen = ((skb->len + 4) % 512) ? 0 : 4;
+ u32 packet_len;
+ u32 padbytes = 0xffff0000;
-static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
+#if (!AX_FORCE_BUFF_ALIGN)
+ int headroom = skb_headroom(skb);
+ int tailroom = skb_tailroom(skb);
+
+ if ((!skb_cloned(skb))
+ && ((headroom + tailroom) >= (4 + padlen))) {
+ if ((headroom < 4) || (tailroom < padlen)) {
+ skb->data = memmove(skb->head + 4, skb->data, skb->len);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ skb->tail = skb->data + skb->len;
+#else
+ skb_set_tail_pointer (skb, skb->len);
+#endif
+ }
+ } else
+#endif
+ {
+ struct sk_buff *skb2;
+ skb2 = skb_copy_expand(skb, 4, padlen, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ skb_push(skb, 4);
+ packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+ cpu_to_le32s(&packet_len);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ memcpy(skb->data, &packet_len, sizeof(packet_len));
+#else
+ skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
+#endif
+
+ if ((skb->len % 512) == 0) {
+ cpu_to_le32s(&padbytes);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ memcpy(skb->tail, &padbytes, sizeof(padbytes));
+#else
+ memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
+#endif
+ skb_put(skb, sizeof(padbytes));
+ }
+ return skb;
+}
+
+static void
+ax88772b_rx_checksum (struct sk_buff *skb, struct ax88772b_rx_header *rx_hdr)
{
- struct asix_data *data = (struct asix_data *)&dev->data;
- int ret;
- u8 buf[ETH_ALEN];
- __le16 eeprom;
- u8 status;
- int gpio0 = 0;
- u32 phyid;
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* checksum error bit is set */
+ if (rx_hdr->l3_csum_err || rx_hdr->l4_csum_err) {
+ return;
+ }
+
+ /* It must be a TCP or UDP packet with a valid checksum */
+ if ((rx_hdr->l4_type == AX_RXHDR_L4_TYPE_TCP) ||
+ (rx_hdr->l4_type == AX_RXHDR_L4_TYPE_UDP)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+}
+
+static int ax88772b_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ struct ax88772b_rx_header rx_hdr;
+ struct sk_buff *ax_skb;
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
- usbnet_get_endpoints(dev,intf);
+ while (skb->len > 0) {
- asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status);
- dbg("GPIO Status: 0x%04x", status);
+ le16_to_cpus((u16 *)skb->data);
+ le16_to_cpus(((u16 *)skb->data) + 1);
- asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
- asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
- asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
+ memcpy (&rx_hdr, skb->data, sizeof (struct ax88772b_rx_header));
- dbg("EEPROM index 0x17 is 0x%04x", eeprom);
+ if ((short)rx_hdr.len != (~((short)rx_hdr.len_bar) & 0x7FF)) {
+ return 0;
+ }
- if (eeprom == cpu_to_le16(0xffff)) {
- data->phymode = PHY_MODE_MARVELL;
- data->ledmode = 0;
- gpio0 = 1;
- } else {
- data->phymode = le16_to_cpu(eeprom) & 7;
- data->ledmode = le16_to_cpu(eeprom) >> 8;
- gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1;
+ if (rx_hdr.len > (ETH_FRAME_LEN + 4)) {
+ deverr(dev, "invalid rx length %d", rx_hdr.len);
+ return 0;
+ }
+
+ if (skb->len - ((rx_hdr.len +
+ sizeof (struct ax88772b_rx_header) + 3) &
+ 0xfffc) == 0) {
+ skb_pull(skb, sizeof (struct ax88772b_rx_header));
+ skb->len = rx_hdr.len;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ skb->tail = skb->data + rx_hdr.len;
+#else
+ skb_set_tail_pointer(skb, rx_hdr.len);
+#endif
+ skb->truesize = rx_hdr.len + sizeof(struct sk_buff);
+
+ if (ax772b_data->checksum & AX_RX_CHECKSUM)
+ ax88772b_rx_checksum (skb, &rx_hdr);
+
+ return 2;
+ }
+
+ ax_skb = skb_clone(skb, GFP_ATOMIC);
+ if (ax_skb) {
+ ax_skb->len = rx_hdr.len;
+ ax_skb->data = skb->data +
+ sizeof (struct ax88772b_rx_header);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ ax_skb->tail = ax_skb->data + rx_hdr.len;
+#else
+ skb_set_tail_pointer(ax_skb, rx_hdr.len);
+#endif
+ ax_skb->truesize = rx_hdr.len + sizeof(struct sk_buff);
+
+ if (ax772b_data->checksum & AX_RX_CHECKSUM) {
+ ax88772b_rx_checksum (ax_skb, &rx_hdr);
+ }
+
+ axusbnet_skb_return(dev, ax_skb);
+
+ } else {
+ return 0;
+ }
+
+ skb_pull(skb, ((rx_hdr.len +
+ sizeof (struct ax88772b_rx_header) + 3)
+ & 0xfffc));
}
- dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode);
- asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
- if ((le16_to_cpu(eeprom) >> 8) != 1) {
- asix_write_gpio(dev, 0x003c, 30);
- asix_write_gpio(dev, 0x001c, 300);
- asix_write_gpio(dev, 0x003c, 30);
- } else {
- dbg("gpio phymode == 1 path");
- asix_write_gpio(dev, AX_GPIO_GPO1EN, 30);
- asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
+ if (skb->len < 0) {
+ deverr(dev, "invalid rx length %d", skb->len);
+ return 0;
}
+ return 1;
+}
- asix_sw_reset(dev, 0);
- msleep(150);
+static struct sk_buff *
+ax88772b_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+ int padlen = ((skb->len + 4) % 512) ? 0 : 4;
+ u32 packet_len;
+ u32 padbytes = 0xffff0000;
- asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
- msleep(150);
+#if (!AX_FORCE_BUFF_ALIGN)
+ int headroom = skb_headroom(skb);
+ int tailroom = skb_tailroom(skb);
- asix_write_rx_ctl(dev, 0);
+ if ((!skb_cloned(skb))
+ && ((headroom + tailroom) >= (4 + padlen))) {
+ if ((headroom < 4) || (tailroom < padlen)) {
+ skb->data = memmove(skb->head + 4, skb->data, skb->len);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ skb->tail = skb->data + skb->len;
+#else
+ skb_set_tail_pointer(skb, skb->len);
+#endif
+ }
+ } else
+#endif
+ {
+ struct sk_buff *skb2;
+ skb2 = skb_copy_expand(skb, 4, padlen, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
- /* Get the MAC address */
- if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
- 0, 0, ETH_ALEN, buf)) < 0) {
- dbg("Failed to read MAC address: %d", ret);
- goto out;
+ skb_push(skb, 4);
+ packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+
+ cpu_to_le32s (&packet_len);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ memcpy(skb->data, &packet_len, sizeof(packet_len));
+#else
+ skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
+#endif
+
+ if ((skb->len % 512) == 0) {
+ cpu_to_le32s (&padbytes);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+ memcpy(skb->tail, &padbytes, sizeof(padbytes));
+#else
+ memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
+#endif
+ skb_put(skb, sizeof(padbytes));
}
- memcpy(dev->net->dev_addr, buf, ETH_ALEN);
- /* Initialize MII structure */
- dev->mii.dev = dev->net;
- dev->mii.mdio_read = asix_mdio_read;
- dev->mii.mdio_write = asix_mdio_write;
- dev->mii.phy_id_mask = 0x1f;
- dev->mii.reg_num_mask = 0xff;
- dev->mii.supports_gmii = 1;
- dev->mii.phy_id = asix_get_phy_addr(dev);
+ return skb;
+}
- dev->net->netdev_ops = &ax88178_netdev_ops;
- dev->net->ethtool_ops = &ax88178_ethtool_ops;
+static const u8 ChkCntSel [6][3] =
+{
+ {12, 23, 31},
+ {12, 31, 23},
+ {23, 31, 12},
+ {23, 12, 31},
+ {31, 12, 23},
+ {31, 23, 12}
+};
- phyid = asix_get_phyid(dev);
- dbg("PHYID=0x%08x", phyid);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void ax88772_link_reset (void *data)
+{
+ struct usbnet *dev = (struct usbnet *)data;
+ struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv;
+#else
+static void ax88772_link_reset (struct work_struct *work)
+{
+ struct ax88772_data *ax772_data = container_of (work,
+ struct ax88772_data, check_link);
+ struct usbnet *dev = ax772_data->dev;
+#endif
+
+ if (ax772_data->Event == AX_SET_RX_CFG) {
+ u16 bmcr;
+ u16 mode;
+
+ ax772_data->Event = AX_NOP;
+
+ mode = AX88772_MEDIUM_DEFAULT;
+
+ bmcr = ax8817x_mdio_read_le(dev->net,
+ dev->mii.phy_id, MII_BMCR);
+ if (!(bmcr & BMCR_FULLDPLX))
+ mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
+ if (!(bmcr & BMCR_SPEED100))
+ mode &= ~AX88772_MEDIUM_100MB;
+
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+ mode, 0, 0, NULL);
+ return;
+ }
+
+ switch (ax772_data->Event) {
+ case WAIT_AUTONEG_COMPLETE:
+ if (jiffies > (ax772_data->autoneg_start + 5 * HZ)) {
+ ax772_data->Event = PHY_POWER_DOWN;
+ ax772_data->TickToExpire = 23;
+ }
+ break;
+ case PHY_POWER_DOWN:
+ if (ax772_data->TickToExpire == 23) {
+ /* Set Phy Power Down */
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD,
+ 0, 0, NULL);
+ --ax772_data->TickToExpire;
+ } else if (--ax772_data->TickToExpire == 0) {
+ /* Set Phy Power Up */
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL, 0, 0, NULL);
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD | AX_SWRESET_IPRL, 0, 0, NULL);
+ msleep(10);
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL, 0, 0, NULL);
+ msleep(60);
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_CLEAR, 0, 0, NULL);
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL, 0, 0, NULL);
+
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id,
+ MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA |
+ ADVERTISE_PAUSE_CAP);
+ mii_nway_restart(&dev->mii);
+
+ ax772_data->Event = PHY_POWER_UP;
+ ax772_data->TickToExpire = 47;
+ }
+ break;
+ case PHY_POWER_UP:
+ if (--ax772_data->TickToExpire == 0) {
+ ax772_data->Event = PHY_POWER_DOWN;
+ ax772_data->TickToExpire = 23;
+ }
+ break;
+ default:
+ break;
+ }
+ return;
+}
- if (data->phymode == PHY_MODE_MARVELL) {
- marvell_phy_init(dev);
- msleep(60);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void ax88772a_link_reset (void *data)
+{
+ struct usbnet *dev = (struct usbnet *)data;
+ struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv;
+#else
+static void ax88772a_link_reset (struct work_struct *work)
+{
+ struct ax88772a_data *ax772a_data = container_of (work,
+ struct ax88772a_data, check_link);
+ struct usbnet *dev = ax772a_data->dev;
+#endif
+ int PowSave = (ax772a_data->EepromData >> 14);
+ u16 phy_reg;
+
+ if (ax772a_data->Event == AX_SET_RX_CFG) {
+ u16 bmcr;
+ u16 mode;
+
+ ax772a_data->Event = AX_NOP;
+
+ mode = AX88772_MEDIUM_DEFAULT;
+
+ bmcr = ax8817x_mdio_read_le(dev->net,
+ dev->mii.phy_id, MII_BMCR);
+ if (!(bmcr & BMCR_FULLDPLX))
+ mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
+ if (!(bmcr & BMCR_SPEED100))
+ mode &= ~AX88772_MEDIUM_100MB;
+
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+ mode, 0, 0, NULL);
+ return;
}
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
- BMCR_RESET | BMCR_ANENABLE);
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ switch (ax772a_data->Event) {
+ case WAIT_AUTONEG_COMPLETE:
+ if (jiffies > (ax772a_data->autoneg_start + 5 * HZ)) {
+ ax772a_data->Event = CHK_CABLE_EXIST;
+ ax772a_data->TickToExpire = 14;
+ }
+ break;
+ case CHK_CABLE_EXIST:
+ phy_reg = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12);
+ if ((phy_reg != 0x8012) && (phy_reg != 0x8013)) {
+ ax8817x_mdio_write_le(dev->net,
+ dev->mii.phy_id, 0x16, 0x4040);
+ mii_nway_restart(&dev->mii);
+ ax772a_data->Event = CHK_CABLE_STATUS;
+ ax772a_data->TickToExpire = 31;
+ } else if (--ax772a_data->TickToExpire == 0) {
+ mii_nway_restart(&dev->mii);
+ ax772a_data->Event = CHK_CABLE_EXIST_AGAIN;
+ if (PowSave == 0x03){
+ ax772a_data->TickToExpire = 47;
+ } else if (PowSave == 0x01) {
+ ax772a_data->DlyIndex = (u8)(jiffies % 6);
+ ax772a_data->DlySel = 0;
+ ax772a_data->TickToExpire =
+ ChkCntSel[ax772a_data->DlyIndex][ax772a_data->DlySel];
+ }
+ }
+ break;
+ case CHK_CABLE_EXIST_AGAIN:
+ /* if cable disconnected */
+ phy_reg = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12);
+ if ((phy_reg != 0x8012) && (phy_reg != 0x8013)) {
+ mii_nway_restart(&dev->mii);
+ ax772a_data->Event = CHK_CABLE_STATUS;
+ ax772a_data->TickToExpire = 31;
+ } else if (--ax772a_data->TickToExpire == 0) {
+ /* Power down PHY */
+ ax8817x_write_cmd(dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPPD,
+ 0, 0, NULL);
+ ax772a_data->Event = PHY_POWER_DOWN;
+ if (PowSave == 0x03){
+ ax772a_data->TickToExpire = 23;
+ } else if (PowSave == 0x01) {
+ ax772a_data->TickToExpire = 31;
+ }
+ }
+ break;
+ case PHY_POWER_DOWN:
+ if (--ax772a_data->TickToExpire == 0) {
+ ax772a_data->Event = PHY_POWER_UP;
+ }
+ break;
+ case CHK_CABLE_STATUS:
+ if (--ax772a_data->TickToExpire == 0) {
+ ax8817x_mdio_write_le(dev->net,
+ dev->mii.phy_id, 0x16, 0x4040);
+ mii_nway_restart(&dev->mii);
+ ax772a_data->Event = CHK_CABLE_EXIST_AGAIN;
+ if (PowSave == 0x03){
+ ax772a_data->TickToExpire = 47;
+ } else if (PowSave == 0x01) {
+ ax772a_data->DlyIndex = (u8)(jiffies % 6);
+ ax772a_data->DlySel = 0;
+ ax772a_data->TickToExpire =
+ ChkCntSel[ax772a_data->DlyIndex][ax772a_data->DlySel];
+ }
+ }
+ break;
+ case PHY_POWER_UP:
+
+ ax88772a_phy_powerup (dev);
+
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
- asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,
- ADVERTISE_1000FULL);
- mii_nway_restart(&dev->mii);
+ mii_nway_restart(&dev->mii);
+
+ ax772a_data->Event = CHK_CABLE_EXIST_AGAIN;
+
+ if (PowSave == 0x03){
+ ax772a_data->TickToExpire = 47;
+
+ } else if (PowSave == 0x01) {
+
+ if (++ax772a_data->DlySel >= 3) {
+ ax772a_data->DlyIndex = (u8)(jiffies % 6);
+ ax772a_data->DlySel = 0;
+ }
+ ax772a_data->TickToExpire =
+ ChkCntSel[ax772a_data->DlyIndex][ax772a_data->DlySel];
+ }
+ break;
+ default:
+ break;
+ }
- if ((ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT)) < 0)
- goto out;
+ return;
+}
- if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
- goto out;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void ax88772b_link_reset (void *data)
+{
+ struct usbnet *dev = (struct usbnet *)data;
+ struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
+#else
+static void ax88772b_link_reset (struct work_struct *work)
+{
+ struct ax88772b_data *ax772b_data = container_of (work,
+ struct ax88772b_data, check_link);
+ struct usbnet *dev = ax772b_data->dev;
+#endif
+
+ switch (ax772b_data->Event) {
+
+ case AX_SET_RX_CFG:
+ {
+ u16 bmcr = ax8817x_mdio_read_le(dev->net,
+ dev->mii.phy_id, MII_BMCR);
+ u16 mode = AX88772_MEDIUM_DEFAULT;
+
+ if (!(bmcr & BMCR_FULLDPLX))
+ mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
+ if (!(bmcr & BMCR_SPEED100))
+ mode &= ~AX88772_MEDIUM_100MB;
+
+ ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+ mode, 0, 0, NULL);
+ break;
+ }
+ case PHY_POWER_UP:
+ {
+ u16 tmp16;
- /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
- if (dev->driver_info->flags & FLAG_FRAMING_AX) {
- /* hard_mtu is still the default - the device does not support
- jumbo eth frames */
- dev->rx_urb_size = 2048;
+ ax88772a_phy_powerup (dev);
+ tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12);
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, 0x12,
+ ((tmp16 & 0xFF9F) | 0x0040));
+
+ ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ break;
+ }
+ case AX_CHK_AUTODETACH:
+ {
+ u16 tmp16;
+ int ret;
+ void *buf;
+ buf = kmalloc(6, GFP_KERNEL);
+ devwarn(dev, "EVENT: AX_CHK_AUTODETACH\n");
+ /* Get the EEPROM data*/
+ if ((ret = ax8817x_read_cmd (dev, AX_CMD_READ_EEPROM,
+ 0x18, 0, 2, (void *)(&tmp16))) < 0) {
+ deverr(dev, "read SROM address 18h failed: %d", ret);
+ }
+ else {
+ ax772b_data->psc = le16_to_cpu(tmp16) & 0xFF00;
+ devwarn(dev, "EEPROM (0x18) = : %04X", ax772b_data->psc);
+ if ((ret = ax8817x_write_cmd (dev, AX_CMD_SW_RESET,
+ AX_SWRESET_IPRL | (ax772b_data->psc & 0x7FFF), 0, 0, buf)) < 0) {
+ deverr(dev, "Failed to configure PHY power saving: %d", ret);
+ }
+ }
+ break;
+ }
+ default:
+ break;
}
+
+ ax772b_data->Event = AX_NOP;
+
+ return;
+}
+
+static int ax88178_set_media(struct usbnet *dev)
+{
+ int ret;
+ struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv;
+ int media;
+
+ media = ax88178_media_check (dev, ax178dataptr);
+ if (media < 0)
+ return media;
+
+ if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
+ media, 0, 0, NULL)) < 0) {
+ deverr(dev, "write mode medium reg failed: %d", ret);
+ return ret;
+ }
+
return 0;
+}
-out:
- return ret;
+static int ax88178_link_reset(struct usbnet *dev)
+{
+ return ax88178_set_media (dev);
+}
+
+static int ax_suspend (struct usb_interface *intf,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
+ pm_message_t message)
+#else
+ u32 message)
+#endif
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+
+ return data->suspend (intf, message);
+}
+
+static int ax_resume (struct usb_interface *intf)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+
+ return data->resume (intf);
}
+static const struct driver_info ax88178_info = {
+ .description = "ASIX AX88178 USB 2.0 Ethernet",
+ .bind = ax88178_bind,
+ .unbind = ax88178_unbind,
+ .status = ax88178_status,
+ .link_reset = ax88178_link_reset,
+ .reset = ax88178_link_reset,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88772_rx_fixup,
+ .tx_fixup = ax88772_tx_fixup,
+};
+
+static const struct driver_info belkin178_info = {
+ .description = "Belkin Gigabit USB 2.0 Network Adapter",
+ .bind = ax88178_bind,
+ .unbind = ax88178_unbind,
+ .status = ax8817x_status,
+ .link_reset = ax88178_link_reset,
+ .reset = ax88178_link_reset,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88772_rx_fixup,
+ .tx_fixup = ax88772_tx_fixup,
+};
+
static const struct driver_info ax8817x_info = {
.description = "ASIX AX8817x USB 2.0 Ethernet",
- .bind = ax88172_bind,
- .status = asix_status,
+ .bind = ax8817x_bind,
+ .status = ax8817x_status,
.link_reset = ax88172_link_reset,
.reset = ax88172_link_reset,
- .flags = FLAG_ETHER | FLAG_LINK_INTR,
- .data = 0x00130103,
+ .flags = FLAG_ETHER,
};
static const struct driver_info dlink_dub_e100_info = {
.description = "DLink DUB-E100 USB Ethernet",
- .bind = ax88172_bind,
- .status = asix_status,
+ .bind = ax8817x_bind,
+ .status = ax8817x_status,
.link_reset = ax88172_link_reset,
.reset = ax88172_link_reset,
- .flags = FLAG_ETHER | FLAG_LINK_INTR,
- .data = 0x009f9d9f,
+ .flags = FLAG_ETHER,
};
static const struct driver_info netgear_fa120_info = {
.description = "Netgear FA-120 USB Ethernet",
- .bind = ax88172_bind,
- .status = asix_status,
+ .bind = ax8817x_bind,
+ .status = ax8817x_status,
.link_reset = ax88172_link_reset,
.reset = ax88172_link_reset,
- .flags = FLAG_ETHER | FLAG_LINK_INTR,
- .data = 0x00130103,
+ .flags = FLAG_ETHER,
};
static const struct driver_info hawking_uf200_info = {
.description = "Hawking UF200 USB Ethernet",
- .bind = ax88172_bind,
- .status = asix_status,
+ .bind = ax8817x_bind,
+ .status = ax8817x_status,
.link_reset = ax88172_link_reset,
.reset = ax88172_link_reset,
- .flags = FLAG_ETHER | FLAG_LINK_INTR,
- .data = 0x001f1d1f,
+ .flags = FLAG_ETHER,
};
static const struct driver_info ax88772_info = {
.description = "ASIX AX88772 USB 2.0 Ethernet",
.bind = ax88772_bind,
- .status = asix_status,
- .link_reset = ax88772_link_reset,
- .reset = ax88772_link_reset,
- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
- .rx_fixup = asix_rx_fixup,
- .tx_fixup = asix_tx_fixup,
+ .unbind = ax88772_unbind,
+ .status = ax88772_status,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88772_rx_fixup,
+ .tx_fixup = ax88772_tx_fixup,
+ .stop = ax88772b_stop,
+ .reset = ax88772b_reset,
};
-static const struct driver_info ax88178_info = {
- .description = "ASIX AX88178 USB 2.0 Ethernet",
- .bind = ax88178_bind,
- .status = asix_status,
- .link_reset = ax88178_link_reset,
- .reset = ax88178_link_reset,
- .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
- .rx_fixup = asix_rx_fixup,
- .tx_fixup = asix_tx_fixup,
+static const struct driver_info dlink_dub_e100b_info = {
+ .description = "D-Link DUB-E100 USB 2.0 Fast Ethernet Adapter",
+ .bind = ax88772_bind,
+ .unbind = ax88772_unbind,
+ .status = ax88772_status,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88772_rx_fixup,
+ .tx_fixup = ax88772_tx_fixup,
+ .stop = ax88772b_stop,
+ .reset = ax88772b_reset,
+};
+
+static const struct driver_info ax88772a_info = {
+ .description = "ASIX AX88772A USB 2.0 Ethernet",
+ .bind = ax88772a_bind,
+ .unbind = ax88772a_unbind,
+ .status = ax88772a_status,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = ax88772_rx_fixup,
+ .tx_fixup = ax88772_tx_fixup,
+ .stop = ax88772b_stop,
+ .reset = ax88772b_reset,
+};
+
+static const struct driver_info ax88772b_info = {
+ .description = "ASIX AX88772B USB 2.0 Ethernet",
+ .bind = ax88772b_bind,
+ .unbind = ax88772b_unbind,
+ .status = ax88772b_status,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT,
+ .rx_fixup = ax88772b_rx_fixup,
+ .tx_fixup = ax88772b_tx_fixup,
+ .stop = ax88772b_stop,
+ .reset = ax88772b_reset,
};
static const struct usb_device_id products [] = {
{
+ // 88178
+ USB_DEVICE (0x0b95, 0x1780),
+ .driver_info = (unsigned long) &ax88178_info,
+}, {
+ // 88178 for billianton linksys
+ USB_DEVICE (0x077b, 0x2226),
+ .driver_info = (unsigned long) &ax88178_info,
+}, {
+ // ABOCOM for linksys
+ USB_DEVICE (0x1737, 0x0039),
+ .driver_info = (unsigned long) &ax88178_info,
+}, {
+ // ABOCOM for pci
+ USB_DEVICE (0x14ea, 0xab11),
+ .driver_info = (unsigned long) &ax88178_info,
+}, {
+ // Belkin
+ USB_DEVICE (0x050d, 0x5055),
+ .driver_info = (unsigned long) &belkin178_info,
+}, {
// Linksys USB200M
USB_DEVICE (0x077b, 0x2226),
.driver_info = (unsigned long) &ax8817x_info,
@@ -1457,6 +3677,14 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x2001, 0x1a00),
.driver_info = (unsigned long) &dlink_dub_e100_info,
}, {
+ // DLink DUB-E100B
+ USB_DEVICE (0x2001, 0x3c05),
+ .driver_info = (unsigned long) &dlink_dub_e100b_info,
+}, {
+ // DLink DUB-E100B
+ USB_DEVICE (0x07d1, 0x3c05),
+ .driver_info = (unsigned long) &dlink_dub_e100b_info,
+}, {
// Intellinet, ST Lab USB Ethernet
USB_DEVICE (0x0b95, 0x1720),
.driver_info = (unsigned long) &ax8817x_info,
@@ -1465,9 +3693,9 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x07b8, 0x420a),
.driver_info = (unsigned long) &hawking_uf200_info,
}, {
- // Billionton Systems, USB2AR
- USB_DEVICE (0x08dd, 0x90ff),
- .driver_info = (unsigned long) &ax8817x_info,
+ // Billionton Systems, USB2AR
+ USB_DEVICE (0x08dd, 0x90ff),
+ .driver_info = (unsigned long) &ax8817x_info,
}, {
// ATEN UC210T
USB_DEVICE (0x0557, 0x2009),
@@ -1477,10 +3705,6 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x0411, 0x003d),
.driver_info = (unsigned long) &ax8817x_info,
}, {
- // Buffalo LUA-U2-GT 10/100/1000
- USB_DEVICE (0x0411, 0x006e),
- .driver_info = (unsigned long) &ax88178_info,
-}, {
// Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter"
USB_DEVICE (0x6189, 0x182d),
.driver_info = (unsigned long) &ax8817x_info,
@@ -1497,86 +3721,53 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x1631, 0x6200),
.driver_info = (unsigned long) &ax8817x_info,
}, {
- // JVC MP-PRX1 Port Replicator
- USB_DEVICE (0x04f1, 0x3008),
- .driver_info = (unsigned long) &ax8817x_info,
-}, {
- // ASIX AX88772B 10/100
- USB_DEVICE (0x0b95, 0x772b),
- .driver_info = (unsigned long) &ax88772_info,
-}, {
// ASIX AX88772 10/100
- USB_DEVICE (0x0b95, 0x7720),
- .driver_info = (unsigned long) &ax88772_info,
-}, {
- // ASIX AX88178 10/100/1000
- USB_DEVICE (0x0b95, 0x1780),
- .driver_info = (unsigned long) &ax88178_info,
-}, {
- // Logitec LAN-GTJ/U2A
- USB_DEVICE (0x0789, 0x0160),
- .driver_info = (unsigned long) &ax88178_info,
-}, {
- // Linksys USB200M Rev 2
- USB_DEVICE (0x13b1, 0x0018),
- .driver_info = (unsigned long) &ax88772_info,
+ USB_DEVICE (0x0b95, 0x7720),
+ .driver_info = (unsigned long) &ax88772_info,
}, {
- // 0Q0 cable ethernet
- USB_DEVICE (0x1557, 0x7720),
- .driver_info = (unsigned long) &ax88772_info,
-}, {
- // DLink DUB-E100 H/W Ver B1
- USB_DEVICE (0x07d1, 0x3c05),
- .driver_info = (unsigned long) &ax88772_info,
-}, {
- // DLink DUB-E100 H/W Ver B1 Alternate
- USB_DEVICE (0x2001, 0x3c05),
- .driver_info = (unsigned long) &ax88772_info,
-}, {
- // Linksys USB1000
- USB_DEVICE (0x1737, 0x0039),
- .driver_info = (unsigned long) &ax88178_info,
+ // ASIX AX88772 10/100
+ USB_DEVICE (0x125E, 0x180D),
+ .driver_info = (unsigned long) &ax88772_info,
}, {
- // IO-DATA ETG-US2
- USB_DEVICE (0x04bb, 0x0930),
- .driver_info = (unsigned long) &ax88178_info,
+ // ASIX AX88772A 10/100
+ USB_DEVICE (0x0b95, 0x772A),
+ .driver_info = (unsigned long) &ax88772a_info,
}, {
- // Belkin F5D5055
- USB_DEVICE(0x050d, 0x5055),
- .driver_info = (unsigned long) &ax88178_info,
+ // ASIX AX88772A 10/100
+ USB_DEVICE (0x0db0, 0xA877),
+ .driver_info = (unsigned long) &ax88772a_info,
}, {
- // Apple USB Ethernet Adapter
- USB_DEVICE(0x05ac, 0x1402),
- .driver_info = (unsigned long) &ax88772_info,
+ // ASIX AX88772A 10/100
+ USB_DEVICE (0x0421, 0x772A),
+ .driver_info = (unsigned long) &ax88772a_info,
}, {
- // Cables-to-Go USB Ethernet Adapter
- USB_DEVICE(0x0b95, 0x772a),
- .driver_info = (unsigned long) &ax88772_info,
+ // Linksys 200M
+ USB_DEVICE (0x13B1, 0x0018),
+ .driver_info = (unsigned long) &ax88772a_info,
}, {
- // ABOCOM for pci
- USB_DEVICE(0x14ea, 0xab11),
- .driver_info = (unsigned long) &ax88178_info,
+ USB_DEVICE (0x05ac, 0x1402),
+ .driver_info = (unsigned long) &ax88772a_info,
}, {
- // ASIX 88772a
- USB_DEVICE(0x0db0, 0xa877),
- .driver_info = (unsigned long) &ax88772_info,
+ // ASIX AX88772B 10/100
+ USB_DEVICE (0x0b95, 0x772B),
+ .driver_info = (unsigned long) &ax88772b_info,
}, {
- // Asus USB Ethernet Adapter
- USB_DEVICE (0x0b95, 0x7e2b),
- .driver_info = (unsigned long) &ax88772_info,
+ // ASIX AX88772B 10/100
+ USB_DEVICE (0x0b95, 0x7E2B),
+ .driver_info = (unsigned long) &ax88772b_info,
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver asix_driver = {
+// .owner = THIS_MODULE,
.name = "asix",
.id_table = products,
- .probe = usbnet_probe,
- .suspend = usbnet_suspend,
- .resume = usbnet_resume,
- .disconnect = usbnet_disconnect,
- .supports_autosuspend = 1,
+ .probe = axusbnet_probe,
+ .suspend = ax_suspend,
+ .resume = ax_resume,
+ .disconnect = axusbnet_disconnect,
};
static int __init asix_init(void)
diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h
new file mode 100644
index 000000000000..ea51eb7001e2
--- /dev/null
+++ b/drivers/net/usb/asix.h
@@ -0,0 +1,558 @@
+#ifndef __LINUX_USBNET_ASIX_H
+#define __LINUX_USBNET_ASIX_H
+
+/*
+ * Turn on this flag if the implementation of your USB host controller
+ * cannot handle non-double word aligned buffer.
+ * When turn on this flag, driver will fixup egress packet aligned on double
+ * word boundary before deliver to USB host controller. And will Disable the
+ * function "skb_reserve (skb, NET_IP_ALIGN)" to retain the buffer aligned on
+ * double word alignment for ingress packets.
+ */
+#define AX_FORCE_BUFF_ALIGN 0
+
+#define AX_MONITOR_MODE 0x01
+#define AX_MONITOR_LINK 0x02
+#define AX_MONITOR_MAGIC 0x04
+#define AX_MONITOR_HSFS 0x10
+
+/* AX88172 Medium Status Register values */
+#define AX_MEDIUM_FULL_DUPLEX 0x02
+#define AX_MEDIUM_TX_ABORT_ALLOW 0x04
+#define AX_MEDIUM_FLOW_CONTROL_EN 0x10
+#define AX_MCAST_FILTER_SIZE 8
+#define AX_MAX_MCAST 64
+
+#define AX_EEPROM_LEN 0x40
+
+#define AX_SWRESET_CLEAR 0x00
+#define AX_SWRESET_RR 0x01
+#define AX_SWRESET_RT 0x02
+#define AX_SWRESET_PRTE 0x04
+#define AX_SWRESET_PRL 0x08
+#define AX_SWRESET_BZ 0x10
+#define AX_SWRESET_IPRL 0x20
+#define AX_SWRESET_IPPD 0x40
+#define AX_SWRESET_IPOSC 0x0080
+#define AX_SWRESET_IPPSL_0 0x0100
+#define AX_SWRESET_IPPSL_1 0x0200
+#define AX_SWRESET_IPCOPS 0x0400
+#define AX_SWRESET_IPCOPSC 0x0800
+#define AX_SWRESET_AUTODETACH 0x1000
+#define AX_SWRESET_WOLLP 0x8000
+
+#define AX88772_IPG0_DEFAULT 0x15
+#define AX88772_IPG1_DEFAULT 0x0c
+#define AX88772_IPG2_DEFAULT 0x0E
+
+#define AX88772A_IPG0_DEFAULT 0x15
+#define AX88772A_IPG1_DEFAULT 0x16
+#define AX88772A_IPG2_DEFAULT 0x1A
+
+#define AX88772_MEDIUM_FULL_DUPLEX 0x0002
+#define AX88772_MEDIUM_RESERVED 0x0004
+#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010
+#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020
+#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080
+#define AX88772_MEDIUM_RX_ENABLE 0x0100
+#define AX88772_MEDIUM_100MB 0x0200
+#define AX88772_MEDIUM_DEFAULT \
+ (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \
+ AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \
+ AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE )
+
+#define AX_CMD_SET_SW_MII 0x06
+#define AX_CMD_READ_MII_REG 0x07
+#define AX_CMD_WRITE_MII_REG 0x08
+#define AX_CMD_SET_HW_MII 0x0a
+#define AX_CMD_READ_EEPROM 0x0b
+#define AX_CMD_WRITE_EEPROM 0x0c
+#define AX_CMD_WRITE_EEPROM_EN 0x0d
+#define AX_CMD_WRITE_EEPROM_DIS 0x0e
+#define AX_CMD_WRITE_RX_CTL 0x10
+#define AX_CMD_READ_IPG012 0x11
+#define AX_CMD_WRITE_IPG0 0x12
+#define AX_CMD_WRITE_IPG1 0x13
+#define AX_CMD_WRITE_IPG2 0x14
+#define AX_CMD_WRITE_MULTI_FILTER 0x16
+#define AX_CMD_READ_NODE_ID 0x17
+#define AX_CMD_READ_PHY_ID 0x19
+#define AX_CMD_READ_MEDIUM_MODE 0x1a
+#define AX_CMD_WRITE_MEDIUM_MODE 0x1b
+#define AX_CMD_READ_MONITOR_MODE 0x1c
+#define AX_CMD_WRITE_MONITOR_MODE 0x1d
+#define AX_CMD_WRITE_GPIOS 0x1f
+#define AX_CMD_SW_RESET 0x20
+#define AX_CMD_SW_PHY_STATUS 0x21
+#define AX_CMD_SW_PHY_SELECT 0x22
+ #define AX_PHYSEL_PSEL (1 << 0)
+ #define AX_PHYSEL_ASEL (1 << 1)
+ #define AX_PHYSEL_SSMII (0 << 2)
+ #define AX_PHYSEL_SSRMII (1 << 2)
+ #define AX_PHYSEL_SSRRMII (3 << 2)
+ #define AX_PHYSEL_SSEN (1 << 4)
+#define AX88772_CMD_READ_NODE_ID 0x13
+#define AX88772_CMD_WRITE_NODE_ID 0x14
+#define AX_CMD_READ_RXCOE_CTL 0x2b
+#define AX_CMD_WRITE_RXCOE_CTL 0x2c
+#define AX_CMD_READ_TXCOE_CTL 0x2d
+#define AX_CMD_WRITE_TXCOE_CTL 0x2e
+
+#define REG_LENGTH 2
+#define PHY_ID_MASK 0x1f
+
+#define AX_RXCOE_IPCE 0x0001
+#define AX_RXCOE_IPVE 0x0002
+#define AX_RXCOE_V6VE 0x0004
+#define AX_RXCOE_TCPE 0x0008
+#define AX_RXCOE_UDPE 0x0010
+#define AX_RXCOE_ICMP 0x0020
+#define AX_RXCOE_IGMP 0x0040
+#define AX_RXCOE_ICV6 0x0080
+#define AX_RXCOE_TCPV6 0x0100
+#define AX_RXCOE_UDPV6 0x0200
+#define AX_RXCOE_ICMV6 0x0400
+#define AX_RXCOE_IGMV6 0x0800
+#define AX_RXCOE_ICV6V6 0x1000
+#define AX_RXCOE_FOPC 0x8000
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)
+#define AX_RXCOE_DEF_CSUM (AX_RXCOE_IPCE | AX_RXCOE_IPVE | \
+ AX_RXCOE_V6VE | AX_RXCOE_TCPE | \
+ AX_RXCOE_UDPE | AX_RXCOE_ICV6 | \
+ AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6)
+#else
+#define AX_RXCOE_DEF_CSUM (AX_RXCOE_IPCE | AX_RXCOE_IPVE | \
+ AX_RXCOE_TCPE | AX_RXCOE_UDPE)
+#endif
+
+#define AX_RXCOE_64TE 0x0100
+#define AX_RXCOE_PPPOE 0x0200
+#define AX_RXCOE_RPCE 0x8000
+
+#define AX_TXCOE_IP 0x0001
+#define AX_TXCOE_TCP 0x0002
+#define AX_TXCOE_UDP 0x0004
+#define AX_TXCOE_ICMP 0x0008
+#define AX_TXCOE_IGMP 0x0010
+#define AX_TXCOE_ICV6 0x0020
+
+#define AX_TXCOE_TCPV6 0x0100
+#define AX_TXCOE_UDPV6 0x0200
+#define AX_TXCOE_ICMV6 0x0400
+#define AX_TXCOE_IGMV6 0x0800
+#define AX_TXCOE_ICV6V6 0x1000
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)
+#define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP | \
+ AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6)
+#else
+#define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP)
+#endif
+
+#define AX_TXCOE_64TE 0x0001
+#define AX_TXCOE_PPPE 0x0002
+
+#define AX88772B_MAX_BULKIN_2K 0
+#define AX88772B_MAX_BULKIN_4K 1
+#define AX88772B_MAX_BULKIN_6K 2
+#define AX88772B_MAX_BULKIN_8K 3
+#define AX88772B_MAX_BULKIN_16K 4
+#define AX88772B_MAX_BULKIN_20K 5
+#define AX88772B_MAX_BULKIN_24K 6
+#define AX88772B_MAX_BULKIN_32K 7
+struct {unsigned short size, byte_cnt,threshold;} AX88772B_BULKIN_SIZE[] =
+{
+ /* 2k */
+ {2048, 0x8000, 0x8001},
+ /* 4k */
+ {4096, 0x8100, 0x8147},
+ /* 6k */
+ {6144, 0x8200, 0x81EB},
+ /* 8k */
+ {8192, 0x8300, 0x83D7},
+ /* 16 */
+ {16384, 0x8400, 0x851E},
+ /* 20k */
+ {20480, 0x8500, 0x8666},
+ /* 24k */
+ {24576, 0x8600, 0x87AE},
+ /* 32k */
+ {32768, 0x8700, 0x8A3D},
+};
+
+
+#define AX_RX_CTL_RH1M 0x0100 /* Enable RX-Header mode 0 */
+#define AX_RX_CTL_RH2M 0x0200 /* Enable IP header in receive buffer aligned on 32-bit aligment */
+#define AX_RX_CTL_RH3M 0x0400 /* checksum value in rx header 3 */
+#define AX_RX_HEADER_DEFAULT (AX_RX_CTL_RH1M | AX_RX_CTL_RH2M)
+
+#define AX_RX_CTL_MFB 0x0300 /* Maximum Frame size 16384bytes */
+#define AX_RX_CTL_START 0x0080 /* Ethernet MAC start */
+#define AX_RX_CTL_AP 0x0020 /* Accept physcial address from Multicast array */
+#define AX_RX_CTL_AM 0x0010
+#define AX_RX_CTL_AB 0x0008 /* Accetp Brocadcast frames*/
+#define AX_RX_CTL_SEP 0x0004 /* Save error packets */
+#define AX_RX_CTL_AMALL 0x0002 /* Accetp all multicast frames */
+#define AX_RX_CTL_PRO 0x0001 /* Promiscuous Mode */
+#define AX_RX_CTL_STOP 0x0000 /* Stop MAC */
+
+#define AX_MONITOR_MODE 0x01
+#define AX_MONITOR_LINK 0x02
+#define AX_MONITOR_MAGIC 0x04
+#define AX_MONITOR_HSFS 0x10
+
+#define AX_MCAST_FILTER_SIZE 8
+#define AX_MAX_MCAST 64
+#define AX_INTERRUPT_BUFSIZE 8
+
+#define AX_EEPROM_LEN 0x40
+#define AX_EEPROM_MAGIC 0xdeadbeef
+#define EEPROMMASK 0x7f
+
+/* GPIO REGISTER */
+#define AXGPIOS_GPO0EN 0X01 // 1 << 0
+#define AXGPIOS_GPO0 0X02 // 1 << 1
+#define AXGPIOS_GPO1EN 0X04 // 1 << 2
+#define AXGPIOS_GPO1 0X08 // 1 << 3
+#define AXGPIOS_GPO2EN 0X10 // 1 << 4
+#define AXGPIOS_GPO2 0X20 // 1 << 5
+#define AXGPIOS_RSE 0X80 // 1 << 7
+
+/* TX-header format */
+#define AX_TX_HDR_CPHI 0x4000
+#define AX_TX_HDR_DICF 0x8000
+
+// GMII register definitions
+#define GMII_PHY_CONTROL 0x00 // control reg
+#define GMII_PHY_STATUS 0x01 // status reg
+#define GMII_PHY_OUI 0x02 // most of the OUI bits
+#define GMII_PHY_MODEL 0x03 // model/rev bits, and rest of OUI
+#define GMII_PHY_ANAR 0x04 // AN advertisement reg
+#define GMII_PHY_ANLPAR 0x05 // AN Link Partner
+#define GMII_PHY_ANER 0x06 // AN expansion reg
+#define GMII_PHY_1000BT_CONTROL 0x09 // control reg for 1000BT
+#define GMII_PHY_1000BT_STATUS 0x0A // status reg for 1000BT
+
+// Bit definitions: GMII Control
+#define GMII_CONTROL_RESET 0x8000 // reset bit in control reg
+#define GMII_CONTROL_LOOPBACK 0x4000 // loopback bit in control reg
+#define GMII_CONTROL_10MB 0x0000 // 10 Mbit
+#define GMII_CONTROL_100MB 0x2000 // 100Mbit
+#define GMII_CONTROL_1000MB 0x0040 // 1000Mbit
+#define GMII_CONTROL_SPEED_BITS 0x2040 // speed bit mask
+#define GMII_CONTROL_ENABLE_AUTO 0x1000 // autonegotiate enable
+#define GMII_CONTROL_POWER_DOWN 0x0800
+#define GMII_CONTROL_ISOLATE 0x0400 // islolate bit
+#define GMII_CONTROL_START_AUTO 0x0200 // restart autonegotiate
+#define GMII_CONTROL_FULL_DUPLEX 0x0100
+
+// Bit definitions: GMII Status
+#define GMII_STATUS_100MB_MASK 0xE000 // any of these indicate 100 Mbit
+#define GMII_STATUS_10MB_MASK 0x1800 // either of these indicate 10 Mbit
+#define GMII_STATUS_AUTO_DONE 0x0020 // auto negotiation complete
+#define GMII_STATUS_AUTO 0x0008 // auto negotiation is available
+#define GMII_STATUS_LINK_UP 0x0004 // link status bit
+#define GMII_STATUS_EXTENDED 0x0001 // extended regs exist
+#define GMII_STATUS_100T4 0x8000 // capable of 100BT4
+#define GMII_STATUS_100TXFD 0x4000 // capable of 100BTX full duplex
+#define GMII_STATUS_100TX 0x2000 // capable of 100BTX
+#define GMII_STATUS_10TFD 0x1000 // capable of 10BT full duplex
+#define GMII_STATUS_10T 0x0800 // capable of 10BT
+
+// Bit definitions: Auto-Negotiation Advertisement
+#define GMII_ANAR_ASYM_PAUSE 0x0800 // support asymetric pause
+#define GMII_ANAR_PAUSE 0x0400 // support pause packets
+#define GMII_ANAR_100T4 0x0200 // support 100BT4
+#define GMII_ANAR_100TXFD 0x0100 // support 100BTX full duplex
+#define GMII_ANAR_100TX 0x0080 // support 100BTX half duplex
+#define GMII_ANAR_10TFD 0x0040 // support 10BT full duplex
+#define GMII_ANAR_10T 0x0020 // support 10BT half duplex
+#define GMII_SELECTOR_FIELD 0x001F // selector field.
+
+// Bit definitions: Auto-Negotiation Link Partner Ability
+#define GMII_ANLPAR_100T4 0x0200 // support 100BT4
+#define GMII_ANLPAR_100TXFD 0x0100 // support 100BTX full duplex
+#define GMII_ANLPAR_100TX 0x0080 // support 100BTX half duplex
+#define GMII_ANLPAR_10TFD 0x0040 // support 10BT full duplex
+#define GMII_ANLPAR_10T 0x0020 // support 10BT half duplex
+#define GMII_ANLPAR_PAUSE 0x0400 // support pause packets
+#define GMII_ANLPAR_ASYM_PAUSE 0x0800 // support asymetric pause
+#define GMII_ANLPAR_ACK 0x4000 // means LCB was successfully rx'd
+#define GMII_SELECTOR_8023 0x0001;
+
+// Bit definitions: 1000BaseT AUX Control
+#define GMII_1000_AUX_CTRL_MASTER_SLAVE 0x1000
+#define GMII_1000_AUX_CTRL_FD_CAPABLE 0x0200 // full duplex capable
+#define GMII_1000_AUX_CTRL_HD_CAPABLE 0x0100 // half duplex capable
+
+// Bit definitions: 1000BaseT AUX Status
+#define GMII_1000_AUX_STATUS_FD_CAPABLE 0x0800 // full duplex capable
+#define GMII_1000_AUX_STATUS_HD_CAPABLE 0x0400 // half duplex capable
+
+// Cicada MII Registers
+#define GMII_AUX_CTRL_STATUS 0x1C
+#define GMII_AUX_ANEG_CPLT 0x8000
+#define GMII_AUX_FDX 0x0020
+#define GMII_AUX_SPEED_1000 0x0010
+#define GMII_AUX_SPEED_100 0x0008
+
+#ifndef ADVERTISE_PAUSE_CAP
+#define ADVERTISE_PAUSE_CAP 0x0400
+#endif
+
+#ifndef MII_STAT1000
+#define MII_STAT1000 0x000A
+#endif
+
+#ifndef LPA_1000FULL
+#define LPA_1000FULL 0x0800
+#endif
+
+// medium mode register
+#define MEDIUM_GIGA_MODE 0x0001
+#define MEDIUM_FULL_DUPLEX_MODE 0x0002
+#define MEDIUM_TX_ABORT_MODE 0x0004
+#define MEDIUM_ENABLE_125MHZ 0x0008
+#define MEDIUM_ENABLE_RX_FLOWCTRL 0x0010
+#define MEDIUM_ENABLE_TX_FLOWCTRL 0x0020
+#define MEDIUM_ENABLE_JUMBO_FRAME 0x0040
+#define MEDIUM_CHECK_PAUSE_FRAME_MODE 0x0080
+#define MEDIUM_ENABLE_RECEIVE 0x0100
+#define MEDIUM_MII_100M_MODE 0x0200
+#define MEDIUM_ENABLE_JAM_PATTERN 0x0400
+#define MEDIUM_ENABLE_STOP_BACKPRESSURE 0x0800
+#define MEDIUM_ENABLE_SUPPER_MAC_SUPPORT 0x1000
+
+/* PHY mode */
+#define PHY_MODE_MARVELL 0
+#define PHY_MODE_CICADA_FAMILY 1
+#define PHY_MODE_CICADA_V1 1
+#define PHY_MODE_AGERE_FAMILY 2
+#define PHY_MODE_AGERE_V0 2
+#define PHY_MODE_CICADA_V2 5
+#define PHY_MODE_AGERE_V0_GMII 6
+#define PHY_MODE_CICADA_V2_ASIX 9
+#define PHY_MODE_VSC8601 10
+#define PHY_MODE_RTL8211CL 12
+#define PHY_MODE_RTL8211BN 13
+#define PHY_MODE_RTL8251CL 14
+#define PHY_MODE_ATTANSIC_V0 0x40
+#define PHY_MODE_ATTANSIC_FAMILY 0x40
+#define PHY_MODE_MAC_TO_MAC_GMII 0x7C
+
+/* */
+#define LED_MODE_MARVELL 0
+#define LED_MODE_CAMEO 1
+
+#define MARVELL_LED_CTRL 0x18
+#define MARVELL_MANUAL_LED 0x19
+
+#define PHY_IDENTIFIER 0x0002
+#define PHY_AGERE_IDENTIFIER 0x0282
+#define PHY_CICADA_IDENTIFIER 0x000f
+#define PHY_MARVELL_IDENTIFIER 0x0141
+
+#define PHY_MARVELL_STATUS 0x001b
+#define MARVELL_STATUS_HWCFG 0x0004 /* SGMII without clock */
+
+#define PHY_MARVELL_CTRL 0x0014
+#define MARVELL_CTRL_RXDELAY 0x0080
+#define MARVELL_CTRL_TXDELAY 0x0002
+
+#define PHY_CICADA_EXTPAGE 0x001f
+#define CICADA_EXTPAGE_EN 0x0001
+#define CICADA_EXTPAGE_DIS 0x0000
+
+
+struct {unsigned short value, offset; } CICADA_FAMILY_HWINIT[] =
+{
+ {0x0001, 0x001f}, {0x1c25, 0x0017}, {0x2a30, 0x001f}, {0x234c, 0x0010},
+ {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0xa7fa, 0x0000},
+ {0x0012, 0x0002}, {0x3002, 0x0001}, {0x87fa, 0x0000}, {0x52b5, 0x001f},
+ {0xafac, 0x0000}, {0x000d, 0x0002}, {0x001c, 0x0001}, {0x8fac, 0x0000},
+ {0x2a30, 0x001f}, {0x0012, 0x0008}, {0x2a30, 0x001f}, {0x0400, 0x0014},
+ {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0xa760, 0x0000},
+ {0x0000, 0x0002}, {0xfaff, 0x0001}, {0x8760, 0x0000}, {0x52b5, 0x001f},
+ {0xa760, 0x0000}, {0x0000, 0x0002}, {0xfaff, 0x0001}, {0x8760, 0x0000},
+ {0x52b5, 0x001f}, {0xafae, 0x0000}, {0x0004, 0x0002}, {0x0671, 0x0001},
+ {0x8fae, 0x0000}, {0x2a30, 0x001f}, {0x0012, 0x0008}, {0x0000, 0x001f},
+};
+
+struct {unsigned short value, offset; } CICADA_V2_HWINIT[] =
+{
+ {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0x000f, 0x0002},
+ {0x472a, 0x0001}, {0x8fa4, 0x0000}, {0x2a30, 0x001f}, {0x0212, 0x0008},
+ {0x0000, 0x001f},
+};
+
+struct {unsigned short value, offset; } CICADA_V2_ASIX_HWINIT[] =
+{
+ {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0x0012, 0x0002},
+ {0x3002, 0x0001}, {0x87fa, 0x0000}, {0x52b5, 0x001f}, {0x000f, 0x0002},
+ {0x472a, 0x0001}, {0x8fa4, 0x0000}, {0x2a30, 0x001f}, {0x0212, 0x0008},
+ {0x0000, 0x001f},
+};
+
+struct {unsigned short value, offset; } AGERE_FAMILY_HWINIT[] =
+{
+ {0x0800, 0x0000}, {0x0007, 0x0012}, {0x8805, 0x0010}, {0xb03e, 0x0011},
+ {0x8808, 0x0010}, {0xe110, 0x0011}, {0x8806, 0x0010}, {0xb03e, 0x0011},
+ {0x8807, 0x0010}, {0xff00, 0x0011}, {0x880e, 0x0010}, {0xb4d3, 0x0011},
+ {0x880f, 0x0010}, {0xb4d3, 0x0011}, {0x8810, 0x0010}, {0xb4d3, 0x0011},
+ {0x8817, 0x0010}, {0x1c00, 0x0011}, {0x300d, 0x0010}, {0x0001, 0x0011},
+ {0x0002, 0x0012},
+};
+
+struct ax88178_data {
+ u16 EepromData;
+ u16 MediaLink;
+ int UseGpio0;
+ int UseRgmii;
+ u8 PhyMode;
+ u8 LedMode;
+ u8 BuffaloOld;
+};
+
+enum watchdog_state {
+ AX_NOP = 0,
+ CHK_LINK, /* Routine A */
+ CHK_CABLE_EXIST, /* Called by A */
+ CHK_CABLE_EXIST_AGAIN, /* Routine B */
+ PHY_POWER_UP, /* Called by B */
+ PHY_POWER_UP_BH,
+ PHY_POWER_DOWN,
+ CHK_CABLE_STATUS, /* Routine C */
+ WAIT_AUTONEG_COMPLETE,
+ AX_SET_RX_CFG,
+ AX_CHK_AUTODETACH,
+};
+
+struct ax88772b_data {
+ struct usbnet *dev;
+ struct workqueue_struct *ax_work;
+ struct work_struct check_link;
+ unsigned long time_to_chk;
+ u16 psc;
+ u8 pw_enabled;
+ u8 Event;
+ u8 checksum;
+ u8 PhySelect:1;
+ u8 OperationMode:1;
+
+};
+
+// define for MAC or PHY mode
+#define OPERATION_MAC_MODE 0
+#define OPERATION_PHY_MODE 1
+
+struct ax88772a_data {
+ struct usbnet *dev;
+ struct workqueue_struct *ax_work;
+ struct work_struct check_link;
+ unsigned long autoneg_start;
+#define AX88772B_WATCHDOG (6 * HZ)
+ u8 Event;
+ u8 TickToExpire;
+ u8 DlyIndex;
+ u8 DlySel;
+ u16 EepromData;
+};
+
+struct ax88772_data {
+ struct usbnet *dev;
+ struct workqueue_struct *ax_work;
+ struct work_struct check_link;
+ unsigned long autoneg_start;
+ u8 Event;
+ u8 TickToExpire;
+};
+
+#define AX_RX_CHECKSUM 1
+#define AX_TX_CHECKSUM 2
+
+/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
+struct ax8817x_data {
+ u8 multi_filter[AX_MCAST_FILTER_SIZE];
+ int (*resume) (struct usb_interface *intf);
+ int (*suspend) (struct usb_interface *intf,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
+ pm_message_t message);
+#else
+ u32 message);
+#endif
+};
+
+struct ax88172_int_data {
+ u16 res1;
+#define AX_INT_PPLS_LINK (1 << 0)
+#define AX_INT_SPLS_LINK (1 << 1)
+#define AX_INT_CABOFF_UNPLUG (1 << 7)
+ u8 link;
+ u16 res2;
+ u8 status;
+ u16 res3;
+} __attribute__ ((packed));
+
+#define AX_RXHDR_L4_ERR (1 << 8)
+#define AX_RXHDR_L3_ERR (1 << 9)
+
+#define AX_RXHDR_L4_TYPE_UDP 1
+#define AX_RXHDR_L4_TYPE_ICMP 2
+#define AX_RXHDR_L4_TYPE_IGMP 3
+#define AX_RXHDR_L4_TYPE_TCP 4
+#define AX_RXHDR_L4_TYPE_TCMPV6 5
+#define AX_RXHDR_L4_TYPE_MASK 7
+
+#define AX_RXHDR_L3_TYPE_IP 1
+#define AX_RXHDR_L3_TYPE_IPV6 2
+
+struct ax88772b_rx_header {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u16 len:11,
+ res1:1,
+ crc:1,
+ mii:1,
+ runt:1,
+ mc_bc:1;
+
+ u16 len_bar:11,
+ res2:5;
+
+ u8 vlan_ind:3,
+ vlan_tag_striped:1,
+ pri:3,
+ res3:1;
+
+ u8 l4_csum_err:1,
+ l3_csum_err:1,
+ l4_type:3,
+ l3_type:2,
+ ce:1;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+ u16 mc_bc:1,
+ runt:1,
+ mii:1,
+ crc:1,
+ res1:1,
+ len:11;
+
+ u16 res2:5,
+ len_bar:11;
+
+ u8 res3:1,
+ pri:3,
+ vlan_tag_striped:1,
+ vlan_ind:3;
+
+ u8 ce:1,
+ l3_type:2,
+ l4_type:3,
+ l3_csum_err:1,
+ l4_csum_err:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+} __attribute__ ((packed));
+
+#endif /* __LINUX_USBNET_ASIX_H */
+
diff --git a/drivers/net/usb/axusbnet.c b/drivers/net/usb/axusbnet.c
new file mode 100644
index 000000000000..00393d38a379
--- /dev/null
+++ b/drivers/net/usb/axusbnet.c
@@ -0,0 +1,1374 @@
+/*
+ * USB Network driver infrastructure
+ * Copyright (C) 2000-2005 by David Brownell
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * This is a generic "USB networking" framework that works with several
+ * kinds of full and high speed networking devices: host-to-host cables,
+ * smart usb peripherals, and actual Ethernet adapters.
+ *
+ * These devices usually differ in terms of control protocols (if they
+ * even have one!) and sometimes they define new framing to wrap or batch
+ * Ethernet packets. Otherwise, they talk to USB pretty much the same,
+ * so interface (un)binding, endpoint I/O queues, fault handling, and other
+ * issues can usefully be addressed by this framework.
+ */
+
+#define DEBUG // error path messages, extra info
+// #define VERBOSE // more; success messages
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ctype.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+/*#include <linux/usb/usbnet.h>*/
+
+#include "asix.h"
+#include "axusbnet.h"
+
+#define DRIVER_VERSION "22-Aug-2005"
+
+static void axusbnet_unlink_rx_urbs(struct usbnet *);
+
+extern void
+ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Nineteen USB 1.1 max size bulk transactions per frame (ms), max.
+ * Several dozen bytes of IPv4 data can fit in two such transactions.
+ * One maximum size Ethernet packet takes twenty four of them.
+ * For high speed, each frame comfortably fits almost 36 max size
+ * Ethernet packets (so queues should be bigger).
+ *
+ * REVISIT qlens should be members of 'struct usbnet'; the goal is to
+ * let the USB host controller be busy for 5msec or more before an irq
+ * is required, under load. Jumbograms change the equation.
+ */
+#define RX_MAX_QUEUE_MEMORY (60 * 1518)
+#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
+ (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4)
+#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
+ (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4)
+
+// reawaken network queue this soon after stopping; else watchdog barks
+//#define TX_TIMEOUT_JIFFIES (5*HZ)
+#define TX_TIMEOUT_JIFFIES (30*HZ)
+
+// throttle rx/tx briefly after some faults, so khubd might disconnect()
+// us (it polls at HZ/4 usually) before we report too many false errors.
+#define THROTTLE_JIFFIES (HZ/8)
+
+// between wakeups
+#define UNLINK_TIMEOUT_MS 3
+
+/*-------------------------------------------------------------------------*/
+
+static const char driver_name [] = "axusbnet";
+
+/* use ethtool to change the level for any given device */
+static int msg_level = -1;
+module_param (msg_level, int, 0);
+MODULE_PARM_DESC (msg_level, "Override default message level");
+
+/*-------------------------------------------------------------------------*/
+
+/* handles CDC Ethernet and many other network "bulk data" interfaces */
+static
+int axusbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
+{
+ int tmp;
+ struct usb_host_interface *alt = NULL;
+ struct usb_host_endpoint *in = NULL, *out = NULL;
+ struct usb_host_endpoint *status = NULL;
+
+ for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
+ unsigned ep;
+
+ in = out = status = NULL;
+ alt = intf->altsetting + tmp;
+
+ /* take the first altsetting with in-bulk + out-bulk;
+ * remember any status endpoint, just in case;
+ * ignore other endpoints and altsetttings.
+ */
+ for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) {
+ struct usb_host_endpoint *e;
+ int intr = 0;
+
+ e = alt->endpoint + ep;
+ switch (e->desc.bmAttributes) {
+ case USB_ENDPOINT_XFER_INT:
+ if (!(e->desc.bEndpointAddress & USB_DIR_IN))
+ continue;
+ intr = 1;
+ /* FALLTHROUGH */
+ case USB_ENDPOINT_XFER_BULK:
+ break;
+ default:
+ continue;
+ }
+ if (e->desc.bEndpointAddress & USB_DIR_IN) {
+ if (!intr && !in)
+ in = e;
+ else if (intr && !status)
+ status = e;
+ } else {
+ if (!out)
+ out = e;
+ }
+ }
+ if (in && out)
+ break;
+ }
+ if (!alt || !in || !out)
+ return -EINVAL;
+
+ if (alt->desc.bAlternateSetting != 0
+ || !(dev->driver_info->flags & FLAG_NO_SETINT)) {
+ tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ if (tmp < 0)
+ return tmp;
+ }
+
+ dev->in = usb_rcvbulkpipe (dev->udev,
+ in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ dev->out = usb_sndbulkpipe (dev->udev,
+ out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ dev->status = status;
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+static void intr_complete (struct urb *urb, struct pt_regs *regs);
+#else
+static void intr_complete (struct urb *urb);
+#endif
+
+static int init_status (struct usbnet *dev, struct usb_interface *intf)
+{
+ char *buf = NULL;
+ unsigned pipe = 0;
+ unsigned maxp;
+ unsigned period;
+
+ if (!dev->driver_info->status)
+ return 0;
+
+ pipe = usb_rcvintpipe (dev->udev,
+ dev->status->desc.bEndpointAddress
+ & USB_ENDPOINT_NUMBER_MASK);
+ maxp = usb_maxpacket (dev->udev, pipe, 0);
+
+ /* avoid 1 msec chatter: min 8 msec poll rate */
+ period = max ((int) dev->status->desc.bInterval,
+ (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3);
+
+ buf = kmalloc (maxp, GFP_KERNEL);
+ if (buf) {
+ dev->interrupt = usb_alloc_urb (0, GFP_KERNEL);
+ if (!dev->interrupt) {
+ kfree (buf);
+ return -ENOMEM;
+ } else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ dev->interrupt->transfer_flags |= URB_ASYNC_UNLINK;
+#endif
+ usb_fill_int_urb(dev->interrupt, dev->udev, pipe,
+ buf, maxp, intr_complete, dev, period);
+ devdbg(dev,
+ "status ep%din, %d bytes period %d",
+ usb_pipeendpoint(pipe), maxp, period);
+ }
+ }
+ return 0;
+}
+
+/* Passes this packet up the stack, updating its accounting.
+ * Some link protocols batch packets, so their rx_fixup paths
+ * can return clones as well as just modify the original skb.
+ */
+static
+void axusbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
+{
+ int status;
+
+ skb->dev = dev->net;
+ skb->protocol = eth_type_trans (skb, dev->net);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+
+ if (netif_msg_rx_status (dev))
+ devdbg (dev, "< rx, len %zu, type 0x%x",
+ skb->len + sizeof (struct ethhdr), skb->protocol);
+ memset (skb->cb, 0, sizeof (struct skb_data));
+ status = netif_rx (skb);
+ if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev))
+ devdbg (dev, "netif_rx status %d", status);
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * Network Device Driver (peer link to "Host Device", from USB host)
+ *
+ *-------------------------------------------------------------------------*/
+
+static
+int axusbnet_change_mtu (struct net_device *net, int new_mtu)
+{
+ struct usbnet *dev = netdev_priv(net);
+ int ll_mtu = new_mtu + net->hard_header_len;
+ int old_hard_mtu = dev->hard_mtu;
+ int old_rx_urb_size = dev->rx_urb_size;
+
+ if (new_mtu <= 0)
+ return -EINVAL;
+ // no second zero-length packet read wanted after mtu-sized packets
+ if ((ll_mtu % dev->maxpacket) == 0)
+ return -EDOM;
+ net->mtu = new_mtu;
+
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+ if (dev->rx_urb_size == old_hard_mtu) {
+ dev->rx_urb_size = dev->hard_mtu;
+ if (dev->rx_urb_size > old_rx_urb_size)
+ axusbnet_unlink_rx_urbs(dev);
+ }
+
+ return 0;
+}
+
+static struct net_device_stats *axusbnet_get_stats (struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv (net);
+ return &dev->stats;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from
+ * completion callbacks. 2.5 should have fixed those bugs...
+ */
+
+static void
+defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&list->lock, flags);
+ __skb_unlink(skb, list);
+ spin_unlock(&list->lock);
+ spin_lock(&dev->done.lock);
+ __skb_queue_tail(&dev->done, skb);
+ if (dev->done.qlen == 1)
+ tasklet_schedule(&dev->bh);
+ spin_unlock_irqrestore(&dev->done.lock, flags);
+}
+
+/* some work can't be done in tasklets, so we use keventd
+ *
+ * NOTE: annoying asymmetry: if it's active, schedule_work() fails,
+ * but tasklet_schedule() doesn't. hope the failure is rare.
+ */
+static
+void axusbnet_defer_kevent (struct usbnet *dev, int work)
+{
+ set_bit (work, &dev->flags);
+ if (!schedule_work (&dev->kevent))
+ deverr (dev, "kevent %d may have been dropped", work);
+ else
+ devdbg (dev, "kevent %d scheduled", work);
+}
+
+/*-------------------------------------------------------------------------*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+static void rx_complete (struct urb *urb, struct pt_regs *regs);
+#else
+static void rx_complete (struct urb *urb);
+#endif
+
+static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
+{
+ struct sk_buff *skb;
+ struct skb_data *entry;
+ int retval = 0;
+ unsigned long lockflags;
+ size_t size = dev->rx_urb_size;
+ struct driver_info *info = dev->driver_info;
+ u8 align;
+
+#if (AX_FORCE_BUFF_ALIGN)
+ align = 0;
+#else
+ if (!(info->flags & FLAG_HW_IP_ALIGNMENT))
+ align = NET_IP_ALIGN;
+ else
+ align = 0;
+#endif
+
+ if ((skb = alloc_skb (size + align, flags)) == NULL) {
+
+ if (netif_msg_rx_err (dev))
+ devdbg (dev, "no rx skb");
+
+ if((dev->rx_urb_size > 2048) && dev->rx_size) {
+ dev->rx_size--;
+ dev->rx_urb_size = AX88772B_BULKIN_SIZE[dev->rx_size].size;
+
+ ax8817x_write_cmd_async (dev, 0x2A,
+ AX88772B_BULKIN_SIZE[dev->rx_size].byte_cnt,
+ AX88772B_BULKIN_SIZE[dev->rx_size].threshold,
+ 0, NULL);
+ }
+
+ if (!(dev->flags & EVENT_RX_MEMORY))
+ axusbnet_defer_kevent (dev, EVENT_RX_MEMORY);
+ usb_free_urb (urb);
+ return;
+ }
+
+ if (align)
+ skb_reserve (skb, NET_IP_ALIGN);
+
+ entry = (struct skb_data *) skb->cb;
+ entry->urb = urb;
+ entry->dev = dev;
+ entry->state = rx_start;
+ entry->length = 0;
+
+ usb_fill_bulk_urb (urb, dev->udev, dev->in,
+ skb->data, size, rx_complete, skb);
+
+ spin_lock_irqsave (&dev->rxq.lock, lockflags);
+
+ if (netif_running (dev->net)
+ && netif_device_present (dev->net)
+ && !test_bit (EVENT_RX_HALT, &dev->flags)) {
+ switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
+ case -EPIPE:
+ axusbnet_defer_kevent (dev, EVENT_RX_HALT);
+ break;
+ case -ENOMEM:
+ axusbnet_defer_kevent (dev, EVENT_RX_MEMORY);
+ break;
+ case -ENODEV:
+ if (netif_msg_ifdown (dev))
+ devdbg (dev, "device gone");
+ netif_device_detach (dev->net);
+ break;
+ default:
+ if (netif_msg_rx_err (dev))
+ devdbg (dev, "rx submit, %d", retval);
+ tasklet_schedule (&dev->bh);
+ break;
+ case 0:
+ __skb_queue_tail (&dev->rxq, skb);
+ }
+ } else {
+ if (netif_msg_ifdown (dev))
+ devdbg (dev, "rx: stopped");
+ retval = -ENOLINK;
+ }
+ spin_unlock_irqrestore (&dev->rxq.lock, lockflags);
+ if (retval) {
+ dev_kfree_skb_any (skb);
+ usb_free_urb (urb);
+ }
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
+{
+ if (dev->driver_info->rx_fixup
+ && !dev->driver_info->rx_fixup (dev, skb))
+ goto error;
+ // else network stack removes extra byte if we forced a short packet
+
+ if (skb->len)
+ axusbnet_skb_return (dev, skb);
+ else {
+ if (netif_msg_rx_err (dev))
+ devdbg (dev, "drop");
+error:
+ dev->stats.rx_errors++;
+ skb_queue_tail (&dev->done, skb);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+static void rx_complete (struct urb *urb, struct pt_regs *regs)
+#else
+static void rx_complete (struct urb *urb)
+#endif
+{
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+ struct skb_data *entry = (struct skb_data *) skb->cb;
+ struct usbnet *dev = entry->dev;
+ int urb_status = urb->status;
+
+ skb_put (skb, urb->actual_length);
+ entry->state = rx_done;
+ entry->urb = NULL;
+
+ switch (urb_status) {
+ /* success */
+ case 0:
+ if (skb->len < dev->net->hard_header_len) {
+ entry->state = rx_cleanup;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+ if (netif_msg_rx_err (dev))
+ devdbg (dev, "rx length %d", skb->len);
+ }
+ break;
+
+ /* stalls need manual reset. this is rare ... except that
+ * when going through USB 2.0 TTs, unplug appears this way.
+ * we avoid the highspeed version of the ETIMEDOUT/EILSEQ
+ * storm, recovering as needed.
+ */
+ case -EPIPE:
+ dev->stats.rx_errors++;
+ axusbnet_defer_kevent (dev, EVENT_RX_HALT);
+ // FALLTHROUGH
+
+ /* software-driven interface shutdown */
+ case -ECONNRESET: /* async unlink */
+ case -ESHUTDOWN: /* hardware gone */
+ if (netif_msg_ifdown (dev))
+ devdbg (dev, "rx shutdown, code %d", urb_status);
+ goto block;
+
+ /* we get controller i/o faults during khubd disconnect() delays.
+ * throttle down resubmits, to avoid log floods; just temporarily,
+ * so we still recover when the fault isn't a khubd delay.
+ */
+ case -EPROTO:
+ case -ETIME:
+ case -EILSEQ:
+ dev->stats.rx_errors++;
+ if (!timer_pending (&dev->delay)) {
+ mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
+ if (netif_msg_link (dev))
+ devdbg (dev, "rx throttle %d", urb_status);
+ }
+block:
+ entry->state = rx_cleanup;
+ entry->urb = urb;
+ urb = NULL;
+ break;
+
+ /* data overrun ... flush fifo? */
+ case -EOVERFLOW:
+ dev->stats.rx_over_errors++;
+ // FALLTHROUGH
+
+ default:
+ entry->state = rx_cleanup;
+ dev->stats.rx_errors++;
+ if (netif_msg_rx_err (dev))
+ devdbg (dev, "rx status %d", urb_status);
+ break;
+ }
+
+ defer_bh(dev, skb, &dev->rxq);
+
+ if (urb) {
+ if (netif_running (dev->net)
+ && !test_bit (EVENT_RX_HALT, &dev->flags)) {
+ rx_submit (dev, urb, GFP_ATOMIC);
+ return;
+ }
+ usb_free_urb (urb);
+ }
+ if (netif_msg_rx_err (dev))
+ devdbg (dev, "no read resubmitted");
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+static void intr_complete (struct urb *urb, struct pt_regs *regs)
+#else
+static void intr_complete (struct urb *urb)
+#endif
+{
+ struct usbnet *dev = urb->context;
+ int status = urb->status;
+
+ switch (status) {
+ /* success */
+ case 0:
+ dev->driver_info->status(dev, urb);
+ break;
+
+ /* software-driven interface shutdown */
+ case -ENOENT: /* urb killed */
+ case -ESHUTDOWN: /* hardware gone */
+ if (netif_msg_ifdown (dev))
+ devdbg (dev, "intr shutdown, code %d", status);
+ return;
+
+ /* NOTE: not throttling like RX/TX, since this endpoint
+ * already polls infrequently
+ */
+ default:
+ devdbg (dev, "intr status %d", status);
+ break;
+ }
+
+ if (!netif_running (dev->net))
+ return;
+
+ memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+ status = usb_submit_urb (urb, GFP_ATOMIC);
+ if (status != 0 && netif_msg_timer (dev))
+ deverr(dev, "intr resubmit --> %d", status);
+}
+
+/*-------------------------------------------------------------------------*/
+
+// unlink pending rx/tx; completion handlers do all other cleanup
+
+static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
+{
+ unsigned long flags;
+ struct sk_buff *skb, *skbnext;
+ int count = 0;
+
+ spin_lock_irqsave (&q->lock, flags);
+ skb_queue_walk_safe(q, skb, skbnext) {
+ struct skb_data *entry;
+ struct urb *urb;
+ int retval;
+
+ entry = (struct skb_data *) skb->cb;
+ urb = entry->urb;
+
+ // during some PM-driven resume scenarios,
+ // these (async) unlinks complete immediately
+ retval = usb_unlink_urb (urb);
+ if (retval != -EINPROGRESS && retval != 0)
+ devdbg (dev, "unlink urb err, %d", retval);
+ else
+ count++;
+ }
+ spin_unlock_irqrestore (&q->lock, flags);
+ return count;
+}
+
+// Flush all pending rx urbs
+// minidrivers may need to do this when the MTU changes
+
+static
+void axusbnet_unlink_rx_urbs(struct usbnet *dev)
+{
+ if (netif_running(dev->net)) {
+ (void) unlink_urbs (dev, &dev->rxq);
+ tasklet_schedule(&dev->bh);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+// precondition: never called in_interrupt
+
+static
+int axusbnet_stop (struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct driver_info *info = dev->driver_info;
+ int temp;
+ int retval;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup);
+#else
+ DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
+#endif
+ DECLARE_WAITQUEUE (wait, current);
+
+ netif_stop_queue (net);
+
+ if (netif_msg_ifdown (dev))
+ devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
+ dev->stats.rx_packets, dev->stats.tx_packets,
+ dev->stats.rx_errors, dev->stats.tx_errors
+ );
+
+ /* allow minidriver to stop correctly (wireless devices to turn off
+ * radio etc) */
+ if (info->stop) {
+ retval = info->stop(dev);
+ if (retval < 0 && netif_msg_ifdown(dev))
+ devinfo(dev,
+ "stop fail (%d) usbnet usb-%s-%s, %s",
+ retval,
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ info->description);
+ }
+
+ if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) {
+ /* ensure there are no more active urbs */
+ add_wait_queue(&unlink_wakeup, &wait);
+ dev->wait = &unlink_wakeup;
+ temp = unlink_urbs(dev, &dev->txq) +
+ unlink_urbs(dev, &dev->rxq);
+
+ /* maybe wait for deletions to finish. */
+ while (!skb_queue_empty(&dev->rxq)
+ && !skb_queue_empty(&dev->txq)
+ && !skb_queue_empty(&dev->done)) {
+ msleep(UNLINK_TIMEOUT_MS);
+ if (netif_msg_ifdown(dev))
+ devdbg(dev, "waited for %d urb completions",
+ temp);
+ }
+ dev->wait = NULL;
+ remove_wait_queue(&unlink_wakeup, &wait);
+ }
+
+ usb_kill_urb(dev->interrupt);
+
+ /* deferred work (task, timer, softirq) must also stop.
+ * can't flush_scheduled_work() until we drop rtnl (later),
+ * else workers could deadlock; so make workers a NOP.
+ */
+ dev->flags = 0;
+ del_timer_sync (&dev->delay);
+ tasklet_kill (&dev->bh);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// posts reads, and enables write queuing
+
+// precondition: never called in_interrupt
+
+static
+int axusbnet_open (struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ int retval = 0;
+ struct driver_info *info = dev->driver_info;
+
+ // put into "known safe" state
+ if (info->reset && (retval = info->reset (dev)) < 0) {
+ if (netif_msg_ifup (dev))
+ devinfo (dev,
+ "open reset fail (%d) usbnet usb-%s-%s, %s",
+ retval,
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ info->description);
+ goto done;
+ }
+
+ // insist peer be connected
+ if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
+ if (netif_msg_ifup (dev))
+ devdbg (dev, "can't open; %d", retval);
+ goto done;
+ }
+
+ /* start any status interrupt transfer */
+ if (dev->interrupt) {
+ retval = usb_submit_urb (dev->interrupt, GFP_KERNEL);
+ if (retval < 0) {
+ if (netif_msg_ifup (dev))
+ deverr (dev, "intr submit %d", retval);
+ goto done;
+ }
+ }
+
+ netif_start_queue (net);
+ if (netif_msg_ifup (dev)) {
+ char *framing;
+
+ if (dev->driver_info->flags & FLAG_FRAMING_NC)
+ framing = "NetChip";
+ else if (dev->driver_info->flags & FLAG_FRAMING_GL)
+ framing = "GeneSys";
+ else if (dev->driver_info->flags & FLAG_FRAMING_Z)
+ framing = "Zaurus";
+ else if (dev->driver_info->flags & FLAG_FRAMING_RN)
+ framing = "RNDIS";
+ else if (dev->driver_info->flags & FLAG_FRAMING_AX)
+ framing = "ASIX";
+ else
+ framing = "simple";
+
+ devinfo (dev, "open: enable queueing "
+ "(rx %d, tx %d) mtu %d %s framing",
+ (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu,
+ framing);
+ }
+
+ // delay posting reads until we're fully open
+ tasklet_schedule (&dev->bh);
+ return retval;
+done:
+ return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ethtool methods; minidrivers may need to add some more, but
+ * they'll probably want to use this base set.
+ */
+
+static
+int axusbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ if (!dev->mii.mdio_read)
+ return -EOPNOTSUPP;
+
+ return mii_ethtool_gset(&dev->mii, cmd);
+}
+
+static
+int axusbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+ int retval;
+
+ if (!dev->mii.mdio_write)
+ return -EOPNOTSUPP;
+
+ retval = mii_ethtool_sset(&dev->mii, cmd);
+
+ /* link speed/duplex might have changed */
+ if (dev->driver_info->link_reset)
+ dev->driver_info->link_reset(dev);
+
+ return retval;
+
+}
+
+static
+u32 axusbnet_get_link (struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ /* If a check_connect is defined, return its result */
+ if (dev->driver_info->check_connect)
+ return dev->driver_info->check_connect (dev) == 0;
+
+ /* if the device has mii operations, use those */
+ if (dev->mii.mdio_read)
+ return mii_link_ok(&dev->mii);
+
+ /* Otherwise, dtrt for drivers calling netif_carrier_{on,off} */
+ return ethtool_op_get_link(net);
+}
+
+static
+int axusbnet_nway_reset(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ if (!dev->mii.mdio_write)
+ return -EOPNOTSUPP;
+
+ return mii_nway_restart(&dev->mii);
+}
+
+static
+void axusbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ strncpy (info->driver, dev->driver_name, sizeof info->driver);
+ strncpy (info->version, DRIVER_VERSION, sizeof info->version);
+ strncpy (info->fw_version, dev->driver_info->description,
+ sizeof info->fw_version);
+ usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info);
+}
+
+static
+u32 axusbnet_get_msglevel (struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return dev->msg_enable;
+}
+
+static
+void axusbnet_set_msglevel (struct net_device *net, u32 level)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ dev->msg_enable = level;
+}
+
+/* drivers may override default ethtool_ops in their bind() routine */
+static struct ethtool_ops axusbnet_ethtool_ops = {
+ .get_settings = axusbnet_get_settings,
+ .set_settings = axusbnet_set_settings,
+ .get_link = axusbnet_get_link,
+ .nway_reset = axusbnet_nway_reset,
+ .get_drvinfo = axusbnet_get_drvinfo,
+ .get_msglevel = axusbnet_get_msglevel,
+ .set_msglevel = axusbnet_set_msglevel,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* work that cannot be done in interrupt context uses keventd.
+ *
+ * NOTE: with 2.5 we could do more of this using completion callbacks,
+ * especially now that control transfers can be queued.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void kevent (void *data)
+{
+ struct usbnet *dev = (struct usbnet *)data;
+#else
+static void kevent (struct work_struct *work)
+{
+ struct usbnet *dev =
+ container_of(work, struct usbnet, kevent);
+#endif
+ int status;
+
+ /* usb_clear_halt() needs a thread context */
+ if (test_bit (EVENT_TX_HALT, &dev->flags)) {
+
+ unlink_urbs (dev, &dev->txq);
+ status = usb_clear_halt (dev->udev, dev->out);
+ if (status < 0
+ && status != -EPIPE
+ && status != -ESHUTDOWN) {
+ if (netif_msg_tx_err (dev))
+ deverr (dev, "can't clear tx halt, status %d",
+ status);
+ } else {
+ clear_bit (EVENT_TX_HALT, &dev->flags);
+ if (status != -ESHUTDOWN)
+ netif_wake_queue (dev->net);
+ }
+ }
+ if (test_bit (EVENT_RX_HALT, &dev->flags)) {
+
+ unlink_urbs (dev, &dev->rxq);
+ status = usb_clear_halt (dev->udev, dev->in);
+ if (status < 0
+ && status != -EPIPE
+ && status != -ESHUTDOWN) {
+ if (netif_msg_rx_err (dev))
+ deverr (dev, "can't clear rx halt, status %d",
+ status);
+ } else {
+ clear_bit (EVENT_RX_HALT, &dev->flags);
+ tasklet_schedule (&dev->bh);
+ }
+ }
+
+ /* tasklet could resubmit itself forever if memory is tight */
+ if (test_bit (EVENT_RX_MEMORY, &dev->flags)) {
+ struct urb *urb = NULL;
+
+ if (netif_running (dev->net))
+ urb = usb_alloc_urb (0, GFP_KERNEL);
+ else
+ clear_bit (EVENT_RX_MEMORY, &dev->flags);
+ if (urb != NULL) {
+ clear_bit (EVENT_RX_MEMORY, &dev->flags);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ urb->transfer_flags |= URB_ASYNC_UNLINK;
+#endif
+ rx_submit (dev, urb, GFP_KERNEL);
+ tasklet_schedule (&dev->bh);
+ }
+ }
+
+ if (test_bit (EVENT_LINK_RESET, &dev->flags)) {
+ struct driver_info *info = dev->driver_info;
+ int retval = 0;
+
+ clear_bit (EVENT_LINK_RESET, &dev->flags);
+ if(info->link_reset && (retval = info->link_reset(dev)) < 0) {
+ devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s",
+ retval,
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ info->description);
+ }
+ }
+
+ if (dev->flags)
+ devdbg (dev, "kevent done, flags = 0x%lx",
+ dev->flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+static void tx_complete (struct urb *urb, struct pt_regs *regs)
+#else
+static void tx_complete (struct urb *urb)
+#endif
+{
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+ struct skb_data *entry = (struct skb_data *) skb->cb;
+ struct usbnet *dev = entry->dev;
+
+ if (urb->status == 0) {
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += entry->length;
+ } else {
+ dev->stats.tx_errors++;
+
+ switch (urb->status) {
+ case -EPIPE:
+ axusbnet_defer_kevent (dev, EVENT_TX_HALT);
+ break;
+
+ /* software-driven interface shutdown */
+ case -ECONNRESET: // async unlink
+ case -ESHUTDOWN: // hardware gone
+ break;
+
+ // like rx, tx gets controller i/o faults during khubd delays
+ // and so it uses the same throttling mechanism.
+ case -EPROTO:
+ case -ETIME:
+ case -EILSEQ:
+ if (!timer_pending (&dev->delay)) {
+ mod_timer (&dev->delay,
+ jiffies + THROTTLE_JIFFIES);
+ if (netif_msg_link (dev))
+ devdbg (dev, "tx throttle %d",
+ urb->status);
+ }
+ netif_stop_queue (dev->net);
+ break;
+ default:
+ if (netif_msg_tx_err (dev))
+ devdbg (dev, "tx err %d", entry->urb->status);
+ break;
+ }
+ }
+
+ urb->dev = NULL;
+ entry->state = tx_done;
+ defer_bh(dev, skb, &dev->txq);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static
+void axusbnet_tx_timeout (struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ unlink_urbs (dev, &dev->txq);
+ tasklet_schedule (&dev->bh);
+
+ // FIXME: device recovery -- reset?
+}
+
+/*-------------------------------------------------------------------------*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+static int
+#else
+static netdev_tx_t
+#endif
+axusbnet_start_xmit (struct sk_buff *skb,
+ struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ int length;
+ struct urb *urb = NULL;
+ struct skb_data *entry;
+ struct driver_info *info = dev->driver_info;
+ unsigned long flags;
+ int retval;
+
+ // some devices want funky USB-level framing, for
+ // win32 driver (usually) and/or hardware quirks
+ if (info->tx_fixup) {
+ skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
+ if (!skb) {
+ if (netif_msg_tx_err (dev))
+ devdbg (dev, "can't tx_fixup skb");
+ goto drop;
+ }
+ }
+ length = skb->len;
+
+ if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
+ if (netif_msg_tx_err (dev))
+ devdbg (dev, "no urb");
+ goto drop;
+ }
+
+ entry = (struct skb_data *) skb->cb;
+ entry->urb = urb;
+ entry->dev = dev;
+ entry->state = tx_start;
+ entry->length = length;
+
+ usb_fill_bulk_urb (urb, dev->udev, dev->out,
+ skb->data, skb->len, tx_complete, skb);
+
+ /* don't assume the hardware handles USB_ZERO_PACKET
+ * NOTE: strictly conforming cdc-ether devices should expect
+ * the ZLP here, but ignore the one-byte packet.
+ */
+ if (!(info->flags & FLAG_SEND_ZLP) && (length % dev->maxpacket) == 0) {
+ urb->transfer_buffer_length++;
+ if (skb_tailroom(skb)) {
+ skb->data[skb->len] = 0;
+ __skb_put(skb, 1);
+ }
+ }
+
+ spin_lock_irqsave (&dev->txq.lock, flags);
+
+ switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
+ case -EPIPE:
+ netif_stop_queue (net);
+ axusbnet_defer_kevent (dev, EVENT_TX_HALT);
+ break;
+ default:
+ if (netif_msg_tx_err (dev))
+ devdbg (dev, "tx: submit urb err %d", retval);
+ break;
+ case 0:
+ net->trans_start = jiffies;
+ __skb_queue_tail (&dev->txq, skb);
+ if (dev->txq.qlen >= TX_QLEN (dev))
+ netif_stop_queue (net);
+ }
+ spin_unlock_irqrestore (&dev->txq.lock, flags);
+
+ if (retval) {
+ if (netif_msg_tx_err (dev))
+ devdbg (dev, "drop, code %d", retval);
+drop:
+ dev->stats.tx_dropped++;
+ if (skb)
+ dev_kfree_skb_any (skb);
+ usb_free_urb (urb);
+ } else if (netif_msg_tx_queued (dev)) {
+ devdbg (dev, "> tx, len %d, type 0x%x",
+ length, skb->protocol);
+ }
+ return NETDEV_TX_OK;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// tasklet (work deferred from completions, in_irq) or timer
+
+static void axusbnet_bh (unsigned long param)
+{
+ struct usbnet *dev = (struct usbnet *) param;
+ struct sk_buff *skb;
+ struct skb_data *entry;
+
+ while ((skb = skb_dequeue (&dev->done))) {
+ entry = (struct skb_data *) skb->cb;
+ switch (entry->state) {
+ case rx_done:
+ entry->state = rx_cleanup;
+ rx_process (dev, skb);
+ continue;
+ case tx_done:
+ case rx_cleanup:
+ usb_free_urb (entry->urb);
+ dev_kfree_skb (skb);
+ continue;
+ default:
+ devdbg (dev, "bogus skb state %d", entry->state);
+ }
+ }
+
+ // waiting for all pending urbs to complete?
+ if (dev->wait) {
+ if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
+ wake_up (dev->wait);
+ }
+
+ // or are we maybe short a few urbs?
+ } else if (netif_running (dev->net)
+ && netif_device_present (dev->net)
+ && !timer_pending (&dev->delay)
+ && !test_bit (EVENT_RX_HALT, &dev->flags)) {
+ int temp = dev->rxq.qlen;
+ int qlen = RX_QLEN (dev);
+
+ if (temp < qlen) {
+ struct urb *urb;
+ int i;
+
+ // don't refill the queue all at once
+ for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) {
+ urb = usb_alloc_urb (0, GFP_ATOMIC);
+ if (urb != NULL) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+ urb->transfer_flags |= URB_ASYNC_UNLINK;
+#endif
+ rx_submit (dev, urb, GFP_ATOMIC);
+ }
+ }
+ if (temp != dev->rxq.qlen && netif_msg_link (dev))
+ devdbg (dev, "rxqlen %d --> %d",
+ temp, dev->rxq.qlen);
+ if (dev->rxq.qlen < qlen)
+ tasklet_schedule (&dev->bh);
+ }
+ if (dev->txq.qlen < TX_QLEN (dev))
+ netif_wake_queue (dev->net);
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ *
+ * USB Device Driver support
+ *
+ *-------------------------------------------------------------------------*/
+
+// precondition: never called in_interrupt
+
+static
+void axusbnet_disconnect (struct usb_interface *intf)
+{
+ struct usbnet *dev;
+ struct usb_device *xdev;
+ struct net_device *net;
+
+ dev = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+ if (!dev)
+ return;
+
+ xdev = interface_to_usbdev (intf);
+
+ if (netif_msg_probe (dev))
+ devinfo (dev, "unregister '%s' usb-%s-%s, %s",
+ intf->dev.driver->name,
+ xdev->bus->bus_name, xdev->devpath,
+ dev->driver_info->description);
+
+ net = dev->net;
+ unregister_netdev (net);
+
+ /* we don't hold rtnl here ... */
+ flush_scheduled_work ();
+
+ if (dev->driver_info->unbind)
+ dev->driver_info->unbind (dev, intf);
+
+ free_netdev(net);
+ usb_put_dev (xdev);
+}
+
+/*-------------------------------------------------------------------------*/
+
+// precondition: never called in_interrupt
+
+static int
+axusbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
+{
+ struct usbnet *dev;
+ struct net_device *net;
+ struct usb_host_interface *interface;
+ struct driver_info *info;
+ struct usb_device *xdev;
+ int status;
+ const char *name;
+
+ name = udev->dev.driver->name;
+ info = (struct driver_info *) prod->driver_info;
+ if (!info) {
+ printk (KERN_ERR "blacklisted by %s\n", name);
+ return -ENODEV;
+ }
+ xdev = interface_to_usbdev (udev);
+ interface = udev->cur_altsetting;
+
+ usb_get_dev (xdev);
+
+ status = -ENOMEM;
+
+ // set up our own records
+ net = alloc_etherdev(sizeof(*dev));
+ if (!net) {
+ dbg ("can't kmalloc dev");
+ goto out;
+ }
+
+ dev = netdev_priv(net);
+ dev->udev = xdev;
+ dev->intf = udev;
+ dev->driver_info = info;
+ dev->driver_name = name;
+ dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
+ | NETIF_MSG_PROBE | NETIF_MSG_LINK);
+ skb_queue_head_init (&dev->rxq);
+ skb_queue_head_init (&dev->txq);
+ skb_queue_head_init (&dev->done);
+ dev->bh.func = axusbnet_bh;
+ dev->bh.data = (unsigned long) dev;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+ INIT_WORK (&dev->kevent, kevent, dev);
+#else
+ INIT_WORK (&dev->kevent, kevent);
+#endif
+
+ dev->delay.function = axusbnet_bh;
+ dev->delay.data = (unsigned long) dev;
+ init_timer (&dev->delay);
+// mutex_init (&dev->phy_mutex);
+
+ dev->net = net;
+
+ /* rx and tx sides can use different message sizes;
+ * bind() should set rx_urb_size in that case.
+ */
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+
+#if 0
+// dma_supported() is deeply broken on almost all architectures
+ // possible with some EHCI controllers
+ if (dma_supported (&udev->dev, DMA_BIT_MASK(64)))
+ net->features |= NETIF_F_HIGHDMA;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+ net->open = axusbnet_open,
+ net->stop = axusbnet_stop,
+ net->hard_start_xmit = axusbnet_start_xmit,
+ net->tx_timeout = axusbnet_tx_timeout,
+ net->get_stats = axusbnet_get_stats;
+#endif
+
+ net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
+ net->ethtool_ops = &axusbnet_ethtool_ops;
+
+ // allow device-specific bind/init procedures
+ // NOTE net->name still not usable ...
+ status = info->bind (dev, udev);
+ if (status < 0) {
+ deverr(dev, "Binding device failed: %d", status);
+ goto out1;
+ }
+
+ /* maybe the remote can't receive an Ethernet MTU */
+ if (net->mtu > (dev->hard_mtu - net->hard_header_len))
+ net->mtu = dev->hard_mtu - net->hard_header_len;
+
+ status = init_status (dev, udev);
+ if (status < 0)
+ goto out3;
+
+ if (!dev->rx_urb_size)
+ dev->rx_urb_size = dev->hard_mtu;
+ dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
+
+ SET_NETDEV_DEV(net, &udev->dev);
+ status = register_netdev (net);
+ if (status) {
+ deverr(dev, "net device registration failed: %d", status);
+ goto out3;
+ }
+
+ if (netif_msg_probe (dev))
+ devinfo (dev, "register '%s' at usb-%s-%s, %s, %pM",
+ udev->dev.driver->name,
+ xdev->bus->bus_name, xdev->devpath,
+ dev->driver_info->description,
+ net->dev_addr);
+
+ // ok, it's ready to go.
+ usb_set_intfdata (udev, dev);
+
+ // start as if the link is up
+ netif_device_attach (net);
+
+ return 0;
+
+out3:
+ if (info->unbind)
+ info->unbind (dev, udev);
+out1:
+ free_netdev(net);
+out:
+ usb_put_dev(xdev);
+ return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * suspend the whole driver as soon as the first interface is suspended
+ * resume only when the last interface is resumed
+ */
+
+static int axusbnet_suspend (struct usb_interface *intf,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
+pm_message_t message)
+#else
+u32 message)
+#endif
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+
+ if (!dev->suspend_count++) {
+ /*
+ * accelerate emptying of the rx and queues, to avoid
+ * having everything error out.
+ */
+ netif_device_detach (dev->net);
+ (void) unlink_urbs (dev, &dev->rxq);
+ (void) unlink_urbs (dev, &dev->txq);
+ /*
+ * reattach so runtime management can use and
+ * wake the device
+ */
+ netif_device_attach (dev->net);
+ }
+ return 0;
+}
+
+static int
+axusbnet_resume (struct usb_interface *intf)
+{
+ struct usbnet *dev = usb_get_intfdata(intf);
+
+ if (!--dev->suspend_count)
+ tasklet_schedule (&dev->bh);
+
+ return 0;
+}
+
diff --git a/drivers/net/usb/axusbnet.h b/drivers/net/usb/axusbnet.h
new file mode 100644
index 000000000000..d492de3b80e1
--- /dev/null
+++ b/drivers/net/usb/axusbnet.h
@@ -0,0 +1,208 @@
+/*
+ * USB Networking Link Interface
+ *
+ * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net>
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __LINUX_USB_USBNET_H
+#define __LINUX_USB_USBNET_H
+
+#ifndef gfp_t
+#define gfp_t int
+#endif
+
+/* interface from usbnet core to each USB networking link we handle */
+struct usbnet {
+ /* housekeeping */
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct driver_info *driver_info;
+ const char *driver_name;
+ void *driver_priv;
+ wait_queue_head_t *wait;
+// struct mutex phy_mutex;
+ unsigned char suspend_count;
+
+ /* i/o info: pipes etc */
+ unsigned in, out;
+ struct usb_host_endpoint *status;
+ unsigned maxpacket;
+ struct timer_list delay;
+
+ /* protocol/interface state */
+ struct net_device *net;
+ struct net_device_stats stats;
+ int msg_enable;
+ unsigned long data [5];
+ u32 xid;
+ u32 hard_mtu; /* count any extra framing */
+ size_t rx_urb_size; /* size for rx urbs */
+ struct mii_if_info mii;
+
+ /* various kinds of pending driver work */
+ struct sk_buff_head rxq;
+ struct sk_buff_head txq;
+ struct sk_buff_head done;
+ struct sk_buff_head rxq_pause;
+ struct urb *interrupt;
+ struct tasklet_struct bh;
+
+ struct work_struct kevent;
+ unsigned long flags;
+# define EVENT_TX_HALT 0
+# define EVENT_RX_HALT 1
+# define EVENT_RX_MEMORY 2
+# define EVENT_STS_SPLIT 3
+# define EVENT_LINK_RESET 4
+# define EVENT_RX_PAUSED 5
+
+ void *priv; /* point to minidriver private data */
+ unsigned char rx_size;
+};
+
+static inline struct usb_driver *driver_of(struct usb_interface *intf)
+{
+ return to_usb_driver(intf->dev.driver);
+}
+
+/* interface from the device/framing level "minidriver" to core */
+struct driver_info {
+ char *description;
+
+ int flags;
+/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */
+#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */
+#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */
+#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */
+#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */
+
+#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */
+#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */
+
+#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */
+#define FLAG_WLAN 0x0080 /* use "wlan%d" names */
+#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */
+#define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */
+#define FLAG_HW_IP_ALIGNMENT 0x0400 /* AX88772B support hardware IP alignment */
+
+
+ /* init device ... can sleep, or cause probe() failure */
+ int (*bind)(struct usbnet *, struct usb_interface *);
+
+ /* cleanup device ... can sleep, but can't fail */
+ void (*unbind)(struct usbnet *, struct usb_interface *);
+
+ /* reset device ... can sleep */
+ int (*reset)(struct usbnet *);
+
+ /* stop device ... can sleep */
+ int (*stop)(struct usbnet *);
+
+ /* see if peer is connected ... can sleep */
+ int (*check_connect)(struct usbnet *);
+
+ /* for status polling */
+ void (*status)(struct usbnet *, struct urb *);
+
+ /* link reset handling, called from defer_kevent */
+ int (*link_reset)(struct usbnet *);
+
+ /* fixup rx packet (strip framing) */
+ int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb);
+
+ /* fixup tx packet (add framing) */
+ struct sk_buff *(*tx_fixup)(struct usbnet *dev,
+ struct sk_buff *skb, gfp_t flags);
+
+ /* early initialization code, can sleep. This is for minidrivers
+ * having 'subminidrivers' that need to do extra initialization
+ * right after minidriver have initialized hardware. */
+ int (*early_init)(struct usbnet *dev);
+
+ /* called by minidriver when receiving indication */
+ void (*indication)(struct usbnet *dev, void *ind, int indlen);
+
+ /* for new devices, use the descriptor-reading code instead */
+ int in; /* rx endpoint */
+ int out; /* tx endpoint */
+
+ unsigned long data; /* Misc driver specific data */
+};
+
+/* Drivers that reuse some of the standard USB CDC infrastructure
+ * (notably, using multiple interfaces according to the CDC
+ * union descriptor) get some helper code.
+ */
+struct cdc_state {
+ struct usb_cdc_header_desc *header;
+ struct usb_cdc_union_desc *u;
+ struct usb_cdc_ether_desc *ether;
+ struct usb_interface *control;
+ struct usb_interface *data;
+};
+
+/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */
+#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
+ |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+ |USB_CDC_PACKET_TYPE_PROMISCUOUS \
+ |USB_CDC_PACKET_TYPE_DIRECTED)
+
+
+/* we record the state for each of our queued skbs */
+enum skb_state {
+ illegal = 0,
+ tx_start, tx_done,
+ rx_start, rx_done, rx_cleanup
+};
+
+struct skb_data { /* skb->cb is one of these */
+ struct urb *urb;
+ struct usbnet *dev;
+ enum skb_state state;
+ size_t length;
+};
+
+#ifndef skb_queue_walk_safe
+#define skb_queue_walk_safe(queue, skb, tmp) \
+ for (skb = (queue)->next, tmp = skb->next; \
+ skb != (struct sk_buff *)(queue); \
+ skb = tmp, tmp = skb->next)
+#endif
+
+/* messaging support includes the interface name, so it must not be
+ * used before it has one ... notably, in minidriver bind() calls.
+ */
+#ifdef DEBUG
+#define devdbg(usbnet, fmt, arg...) \
+ printk("%s: " fmt "\n" , (usbnet)->net->name , ## arg)
+#else
+#define devdbg(usbnet, fmt, arg...) \
+ ({ if (0) printk("%s: " fmt "\n" , (usbnet)->net->name , \
+ ## arg); 0; })
+#endif
+
+#define deverr(usbnet, fmt, arg...) \
+ printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
+#define devwarn(usbnet, fmt, arg...) \
+ printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg)
+
+#define devinfo(usbnet, fmt, arg...) \
+ printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \
+
+
+#endif /* __LINUX_USB_USBNET_H */
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index 9ab8f3fb68ef..c9cac10c6a3e 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -64,6 +64,7 @@ struct tps6586x_regulator {
int enable_reg[2];
int *voltages;
int delay; /* delay in us for regulator to stabilize */
+ enum tps6586x_type type;
/* for DVM regulators */
int go_reg;
@@ -236,6 +237,13 @@ static int tps6586x_sm2_voltages[] = {
4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550,
};
+static int tps6586x_sm2fortythree_voltages[] = {
+ 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200,
+ 1225, 1250, 1275, 1300, 1325, 1350, 1375, 1400,
+ 1425, 1450, 1475, 1500, 1525, 1550, 1575, 1600,
+ 1625, 1650, 1675, 1700, 1725, 1750, 1775, 1800,
+};
+
static int tps6586x_dvm_voltages[] = {
725, 750, 775, 800, 825, 850, 875, 900,
925, 950, 975, 1000, 1025, 1050, 1075, 1100,
@@ -243,7 +251,7 @@ static int tps6586x_dvm_voltages[] = {
1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
};
-#define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits, \
+#define TPS6586X_REGULATOR(_id, _type, vdata, _ops, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, en_time) \
.desc = { \
.name = "REG-" #_id, \
@@ -261,43 +269,62 @@ static int tps6586x_dvm_voltages[] = {
.enable_reg[1] = TPS6586X_SUPPLY##ereg1, \
.enable_bit[1] = (ebit1), \
.voltages = tps6586x_##vdata##_voltages, \
- .delay = en_time,
+ .delay = en_time, \
+ .type = (_type),
#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
.go_reg = TPS6586X_##goreg, \
.go_bit = (gobit),
-#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \
+#define TPS6586X_LDO(_id, type, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, en_time) \
{ \
- TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1, en_time) \
+ TPS6586X_REGULATOR(_id, type, vdata, ldo_ops, vreg, shift, \
+ nbits, ereg0, ebit0, ereg1, ebit1, en_time) \
}
-#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \
+#define TPS6586X_DVM(_id, type, vdata, vreg, shift, nbits, \
ereg0, ebit0, ereg1, ebit1, goreg, gobit, en_time) \
{ \
- TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits, \
- ereg0, ebit0, ereg1, ebit1, en_time) \
+ TPS6586X_REGULATOR(_id, type, vdata, dvm_ops, vreg, shift, \
+ nbits, ereg0, ebit0, ereg1, ebit1, en_time) \
TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \
}
+/* Note: type ANY means universal, search order matters, place ANY last */
static struct tps6586x_regulator tps6586x_regulator[] = {
- TPS6586X_LDO(LDO_0, ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0, 4000),
- TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1, 4000),
- TPS6586X_LDO(LDO_3, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2, 3000),
- TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6, 3000),
- TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4, 15000),
- TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5, 15000),
- TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6, 15000),
- TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7, 3000),
- TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7, 0),
- TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7, 0),
-
- TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6, 3000),
- TPS6586X_DVM(SM_0, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2, 4000),
- TPS6586X_DVM(SM_1, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0, 4000),
- TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6, 15000),
+ TPS6586X_LDO(LDO_0, TPS6586X_ANY, ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0,
+ 4000),
+ TPS6586X_LDO(LDO_1, TPS6586X_ANY, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1,
+ 4000),
+ TPS6586X_DVM(LDO_2, TPS6586X_ANY, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3,
+ VCC2, 6, 3000),
+ TPS6586X_LDO(LDO_3, TPS6586X_ANY, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2,
+ 3000),
+ TPS6586X_DVM(LDO_4, TPS6586X_ANY, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3,
+ VCC1, 6, 15000),
+ TPS6586X_LDO(LDO_5, TPS6586X_ANY, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6,
+ 3000),
+ TPS6586X_LDO(LDO_6, TPS6586X_ANY, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4,
+ 15000),
+ TPS6586X_LDO(LDO_7, TPS6586X_ANY, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5,
+ 15000),
+ TPS6586X_LDO(LDO_8, TPS6586X_ANY, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6,
+ 15000),
+ TPS6586X_LDO(LDO_9, TPS6586X_ANY, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7,
+ 3000),
+ TPS6586X_LDO(LDO_RTC, TPS6586X_ANY, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7,
+ 0),
+ TPS6586X_DVM(SM_0, TPS6586X_ANY, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1,
+ VCC1, 2, 4000),
+ TPS6586X_DVM(SM_1, TPS6586X_ANY, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0,
+ VCC1, 0, 4000),
+ TPS6586X_DVM(SM_2, TPS658623, ldo4, SUPPLYV2, 0, 5, ENC, 3, END, 3,
+ VCC1, 6, 15000),
+ TPS6586X_DVM(SM_2, TPS658643, sm2fortythree, SUPPLYV2, 0, 5, ENC, 3,
+ END, 3, VCC1, 6, 15000),
+ TPS6586X_LDO(SM_2, TPS6586X_ANY, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7,
+ 0),
};
/*
@@ -399,14 +426,16 @@ static inline int tps6586x_regulator_set_slew_rate(struct platform_device *pdev)
return tps6586x_write(parent, reg, setting->slew_rate);
}
-static inline struct tps6586x_regulator *find_regulator_info(int id)
+static inline struct tps6586x_regulator *find_regulator_info(int id,
+ enum tps6586x_type type)
{
struct tps6586x_regulator *ri;
int i;
for (i = 0; i < ARRAY_SIZE(tps6586x_regulator); i++) {
ri = &tps6586x_regulator[i];
- if (ri->desc.id == id)
+ if ((ri->desc.id == id) && ((ri->type == type) ||
+ (ri->type == TPS6586X_ANY)))
return ri;
}
return NULL;
@@ -421,7 +450,7 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Probing reulator %d\n", id);
- ri = find_regulator_info(id);
+ ri = find_regulator_info(id, tps6586x_gettype(pdev->dev.parent));
if (ri == NULL) {
dev_err(&pdev->dev, "invalid regulator ID specified\n");
return -EINVAL;
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index b39f2e1c1fe6..ce9761c79c51 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -205,3 +205,10 @@ config MAX1363_RING_BUFFER
help
Say yes here to include ring buffer support in the MAX1363
ADC driver.
+
+config STMPE_ADC
+ bool "ST Microelectronics STMPE ADC driver"
+ depends on MFD_STMPE
+ help
+ Say yes here to build support for ST Microelectronics STMPE
+ built in ADC block (stmpe811).
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index f02035139979..e54101c03121 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -40,3 +40,5 @@ obj-$(CONFIG_AD7816) += ad7816.o
obj-$(CONFIG_ADT75) += adt75.o
obj-$(CONFIG_ADT7310) += adt7310.o
obj-$(CONFIG_ADT7410) += adt7410.o
+
+obj-$(CONFIG_STMPE_ADC) += stmpe-adc.o
diff --git a/drivers/staging/iio/adc/stmpe-adc.c b/drivers/staging/iio/adc/stmpe-adc.c
new file mode 100644
index 000000000000..3a9d6bee558d
--- /dev/null
+++ b/drivers/staging/iio/adc/stmpe-adc.c
@@ -0,0 +1,334 @@
+/*
+ * stmpe.c - STMicroelectronics STMPE811 IIO ADC Driver
+ *
+ * 4 channel, 10/12-bit ADC
+ *
+ * Copyright (C) 2013 Toradex AG <stefan.agner@toradex.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_platform.h>
+#include <linux/err.h>
+
+#include <linux/mfd/stmpe.h>
+
+#include "../iio.h"
+#include "adc.h"
+
+#define STMPE_REG_INT_STA 0x0B
+#define STMPE_REG_ADC_INT_EN 0x0E
+#define STMPE_REG_ADC_INT_STA 0x0F
+
+#define STMPE_REG_ADC_CTRL1 0x20
+#define STMPE_REG_ADC_CTRL2 0x21
+#define STMPE_REG_ADC_CAPT 0x22
+#define STMPE_REG_ADC_DATA_CH(channel) (0x30 + 2*channel)
+
+#define STMPE_ADC_CH(channel) ((1 << channel) & 0xff)
+
+#define STMPE_ADC_TIMEOUT (msecs_to_jiffies(1000))
+
+struct stmpe_adc {
+ struct stmpe *stmpe;
+ struct clk *clk;
+ struct device *dev;
+ unsigned int irq;
+
+ struct completion completion;
+
+ u8 channel;
+ u32 value;
+ u8 sample_time;
+ u8 mod_12b;
+ u8 ref_sel;
+ u8 adc_freq;
+};
+
+static int stmpe_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct stmpe_adc *info = iio_priv(indio_dev);
+ unsigned long timeout;
+
+ if (mask > 0)
+ return -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+
+ info->channel = (u8)chan->scan_index;
+ stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_EN,
+ STMPE_ADC_CH(info->channel));
+
+ stmpe_reg_write(info->stmpe, STMPE_REG_ADC_CAPT,
+ STMPE_ADC_CH(info->channel));
+
+ timeout = wait_for_completion_interruptible_timeout
+ (&info->completion, STMPE_ADC_TIMEOUT);
+
+ *val = info->value;
+
+ mutex_unlock(&indio_dev->mlock);
+
+ if (timeout == -ERESTARTSYS)
+ return -EINTR;
+
+ if (timeout == 0)
+ return -ETIMEDOUT;
+
+ return IIO_VAL_INT;
+}
+
+static irqreturn_t stmpe_adc_isr(int irq, void *dev_id)
+{
+ struct stmpe_adc *info = (struct stmpe_adc *)dev_id;
+ u8 data[2];
+ int int_sta;
+
+ int_sta = stmpe_reg_read(info->stmpe, STMPE_REG_ADC_INT_STA);
+
+ /* Is the interrupt relevant */
+ if (!(int_sta & STMPE_ADC_CH(info->channel)))
+ return IRQ_NONE;
+
+ /* Read value */
+ stmpe_block_read(info->stmpe, STMPE_REG_ADC_DATA_CH(info->channel), 2,
+ data);
+ info->value = ((u32)data[0] << 8) + data[1];
+
+ stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA, int_sta);
+
+ complete(&info->completion);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_info stmpe_adc_iio_info = {
+ .num_interrupt_lines = 1,
+ .read_raw = &stmpe_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+#define STMPE_EV_M \
+ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \
+ | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
+#define STMPE_INFO_MASK (1 << IIO_CHAN_INFO_SCALE_SHARED)
+
+static const struct iio_chan_spec stmpe_adc_all_iio_channels[] = {
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, STMPE_INFO_MASK,
+ 0, 0, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 1, 0, STMPE_INFO_MASK,
+ 0, 1, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 2, 0, STMPE_INFO_MASK,
+ 0, 2, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 3, 0, STMPE_INFO_MASK,
+ 0, 3, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 4, 0, STMPE_INFO_MASK,
+ 0, 4, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 5, 0, STMPE_INFO_MASK,
+ 0, 5, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 6, 0, STMPE_INFO_MASK,
+ 0, 6, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 7, 0, STMPE_INFO_MASK,
+ 0, 7, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+};
+
+static const struct iio_chan_spec stmpe_adc_iio_channels[] = {
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 4, 0, STMPE_INFO_MASK,
+ 0, 4, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 5, 0, STMPE_INFO_MASK,
+ 0, 5, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 6, 0, STMPE_INFO_MASK,
+ 0, 6, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+ IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 7, 0, STMPE_INFO_MASK,
+ 0, 7, IIO_ST('u', 12, 16, 0), STMPE_EV_M),
+};
+
+static int stmpe_adc_remove_devices(struct device *dev, void *c)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
+
+ return 0;
+}
+
+static int __devinit stmpe_adc_init_hw(struct stmpe_adc *adc)
+{
+ int ret;
+ u8 adc_ctrl1, adc_ctrl1_mask;
+ struct stmpe *stmpe = adc->stmpe;
+ struct device *dev = adc->dev;
+
+ ret = stmpe_enable(stmpe, STMPE_BLOCK_ADC);
+ if (ret) {
+ dev_err(dev, "Could not enable clock for ADC\n");
+ return ret;
+ }
+
+ adc_ctrl1 = SAMPLE_TIME(adc->sample_time) | MOD_12B(adc->mod_12b) |
+ REF_SEL(adc->ref_sel);
+ adc_ctrl1_mask = SAMPLE_TIME(0xff) | MOD_12B(0xff) | REF_SEL(0xff);
+
+ ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1,
+ adc_ctrl1_mask, adc_ctrl1);
+ if (ret) {
+ dev_err(dev, "Could not setup ADC\n");
+ return ret;
+ }
+
+ ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2,
+ ADC_FREQ(0xff), ADC_FREQ(adc->adc_freq));
+ if (ret) {
+ dev_err(dev, "Could not setup ADC\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int __devinit stmpe_adc_probe(struct platform_device *pdev)
+{
+ struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+ struct stmpe_platform_data *pdata = stmpe->pdata;
+ struct stmpe_adc_platform_data *adc_pdata = NULL;
+ struct stmpe_adc *info = NULL;
+ struct iio_dev *indio_dev = NULL;
+ int ret = -ENODEV;
+ int irq;
+
+ irq = platform_get_irq_byname(pdev, "STMPE_ADC");
+ if (irq < 0)
+ return irq;
+
+ indio_dev = iio_allocate_device(sizeof(struct stmpe_adc));
+ if (!indio_dev) {
+ dev_err(&pdev->dev, "failed allocating iio device\n");
+ return -ENOMEM;
+ }
+
+ info = iio_priv(indio_dev);
+ info->irq = irq;
+ info->stmpe = stmpe;
+
+ init_completion(&info->completion);
+ ret = request_threaded_irq(info->irq, NULL, stmpe_adc_isr, IRQF_ONESHOT,
+ "stmpe-adc", info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
+ info->irq);
+ goto err_free;
+ }
+ platform_set_drvdata(pdev, indio_dev);
+
+ indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &stmpe_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* Register TS-Channels only if they are available */
+ if (stmpe->pdata->blocks & STMPE_BLOCK_TOUCHSCREEN)
+ indio_dev->channels = stmpe_adc_iio_channels;
+ else
+ indio_dev->channels = stmpe_adc_all_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(stmpe_adc_iio_channels);
+
+ if (pdata)
+ adc_pdata = pdata->adc;
+
+ if (adc_pdata) {
+ info->sample_time = adc_pdata->sample_time;
+ info->mod_12b = adc_pdata->mod_12b;
+ info->ref_sel = adc_pdata->ref_sel;
+ info->adc_freq = adc_pdata->adc_freq;
+ }
+
+ ret = stmpe_adc_init_hw(info);
+ if (ret)
+ goto err_irq;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err_irq;
+
+
+ dev_info(&pdev->dev, "Initialized\n");
+
+ return 0;
+
+err_irq:
+ free_irq(info->irq, info);
+err_free:
+ kfree(indio_dev);
+ return ret;
+}
+
+static int stmpe_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct stmpe_adc *info = iio_priv(indio_dev);
+
+ device_for_each_child(&pdev->dev, NULL,
+ stmpe_adc_remove_devices);
+ iio_device_unregister(indio_dev);
+ free_irq(info->irq, info);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stmpe_adc_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct stmpe_adc *info = iio_priv(indio_dev);
+
+ stmpe_adc_init_hw(info);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stmpe_adc_pm_ops, NULL, stmpe_adc_resume);
+
+static struct platform_driver stmpe_adc_driver = {
+ .probe = stmpe_adc_probe,
+ .remove = stmpe_adc_remove,
+ .driver = {
+ .name = "stmpe-adc",
+ .owner = THIS_MODULE,
+ .pm = &stmpe_adc_pm_ops,
+ },
+};
+
+module_platform_driver(stmpe_adc_driver);
+
+MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
+MODULE_DESCRIPTION("STMPEXXX ADC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:stmpe-adc");
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
index 19819e7578c6..fd812c343e81 100644
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/staging/iio/industrialio-core.c
@@ -860,7 +860,10 @@ static ssize_t iio_ev_state_show(struct device *dev,
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- int val = indio_dev->info->read_event_config(indio_dev,
+ int val = -ENODEV;
+
+ if (indio_dev->info != NULL && indio_dev->info->read_event_config != NULL)
+ val = indio_dev->info->read_event_config(indio_dev,
this_attr->address);
if (val < 0)
@@ -875,9 +878,10 @@ static ssize_t iio_ev_value_show(struct device *dev,
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- int val, ret;
+ int val, ret = -ENODEV;
- ret = indio_dev->info->read_event_value(indio_dev,
+ if (indio_dev->info != NULL && indio_dev->info->read_event_config != NULL)
+ ret = indio_dev->info->read_event_value(indio_dev,
this_attr->address, &val);
if (ret < 0)
return ret;
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index a3f966b39862..295fd2d7c713 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -1641,6 +1641,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
struct irq_info *i = dev_id;
struct list_head *l, *end = NULL;
int pass_counter = 0, handled = 0;
+ static unsigned int tegra_spurious = 0;
DEBUG_INTR("serial8250_interrupt(%d)...", irq);
@@ -1674,6 +1675,26 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
handled = 1;
end = NULL;
+ } else if ((up->port.type == PORT_TEGRA) && !handled) {
+ /* irq 68: nobody cared workaround */
+
+ /* The irq request flag sometimes does not get reset or is
+ * asserted immediately, but iir does not indicated this, if
+ * so we get here with iir set to 0xc1, i.e. no irq pending. */
+
+ /* Try enabling the transmit register empty interrupt,
+ * iir becomes 0xc2, irq gets de-asserted and ier is reverted
+ * by the regular code flow in the ISR. */
+ tegra_spurious++;
+ /* Try this every 4096 spurious irq. */
+ if ((tegra_spurious % 0x1000) == 0xfff) {
+ up->ier |= UART_IER_THRI;
+ serial_out(up, UART_IER, up->ier);
+ udelay(1);
+ handled = 1;
+ end = NULL;
+ } else if (end == NULL)
+ end = l;
} else if (end == NULL)
end = l;
diff --git a/drivers/tty/serial/tegra_hsuart.c b/drivers/tty/serial/tegra_hsuart.c
index b2fa281492a7..3f38cca3d6ec 100644
--- a/drivers/tty/serial/tegra_hsuart.c
+++ b/drivers/tty/serial/tegra_hsuart.c
@@ -819,7 +819,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t)
* Initialize the UART for a simple default configuration
* so that the receive DMA buffer may be enqueued */
t->lcr_shadow = 3; /* no parity, stop, 8 data bits */
- tegra_set_baudrate(t, 115200);
+ tegra_set_baudrate(t, 9600);
t->fcr_shadow |= UART_FCR_DMA_SELECT;
uart_writeb(t, t->fcr_shadow, UART_FCR);
if (tegra_start_dma_rx(t)) {
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 7b3185ff188a..9f79c267890e 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -399,8 +399,8 @@ static int rndis_function_bind_config(struct android_usb_function *f,
rndis_control_intf.bInterfaceProtocol = 0x03;
}
- return rndis_bind_config(c, rndis->ethaddr, rndis->vendorID,
- rndis->manufacturer);
+ return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID,
+ rndis->manufacturer);
}
static void rndis_function_unbind_config(struct android_usb_function *f,
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index f187b9eee9e5..25cb5fc8b263 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -774,9 +774,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0);
rndis_set_host_mac(rndis->config, rndis->ethaddr);
- if (rndis_set_param_vendor(rndis->config, rndis->vendorID,
- rndis->manufacturer))
- goto fail;
+ if (rndis->manufacturer && rndis->vendorID &&
+ rndis_set_param_vendor(rndis->config, rndis->vendorID,
+ rndis->manufacturer))
+ goto fail;
/* NOTE: all that is done without knowing or caring about
* the network link ... which is unavailable to this code
@@ -844,20 +845,8 @@ static inline bool can_support_rndis(struct usb_configuration *c)
return true;
}
-/**
- * rndis_bind_config - add RNDIS network link to a configuration
- * @c: the configuration to support the network link
- * @ethaddr: a buffer in which the ethernet address of the host side
- * side of the link was recorded
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- *
- * Caller must have called @gether_setup(). Caller is also responsible
- * for calling @gether_cleanup() before module unload.
- */
int
-rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
u32 vendorID, const char *manufacturer)
{
struct f_rndis *rndis;
diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c
index c130dae3a8e9..074a9b1ce6d9 100644
--- a/drivers/usb/gadget/tegra_udc.c
+++ b/drivers/usb/gadget/tegra_udc.c
@@ -52,8 +52,8 @@
#include "tegra_udc.h"
-#define DRIVER_DESC "Nvidia Tegra High-Speed USB SOC \
- Device Controller driver"
+#define DRIVER_DESC "Nvidia Tegra High-Speed USB SOC " \
+ "Device Controller driver"
#define DRIVER_AUTHOR "Venkat Moganty/Rakesh Bodla"
#define DRIVER_VERSION "Apr 30, 2012"
@@ -95,6 +95,11 @@ static const u8 tegra_udc_test_packet[53] = {
0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e
};
+#ifdef CONFIG_MACH_COLIBRI_T20
+/* To limit the speed of USB to full speed */
+extern int g_usb_high_speed;
+#endif /* CONFIG_MACH_COLIBRI_T20 */
+
static struct tegra_udc *the_udc;
#ifdef CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ
@@ -253,6 +258,16 @@ static int dr_controller_reset(struct tegra_udc *udc)
cpu_relax();
}
+#ifdef CONFIG_MACH_COLIBRI_T20
+ /* To limit the speed of USB to full speed */
+ if (!g_usb_high_speed) {
+ tmp = udc_readl(udc, PORTSCX_REG_OFFSET);
+ tmp |= PORTSCX_PORT_FORCE_FULL_SPEED;
+ udc_writel(udc, tmp, PORTSCX_REG_OFFSET);
+ tmp = udc_readl(udc, PORTSCX_REG_OFFSET);
+ }
+#endif /* CONFIG_MACH_COLIBRI_T20 */
+
DBG("%s(%d) END\n", __func__, __LINE__);
return 0;
}
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 46772413f0db..c32227ebac0b 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -111,13 +111,13 @@ int eem_bind_config(struct usb_configuration *c);
#ifdef USB_ETH_RNDIS
-int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
u32 vendorID, const char *manufacturer);
#else
static inline int
-rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
u32 vendorID, const char *manufacturer)
{
return 0;
@@ -125,4 +125,23 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
#endif
+/**
+ * rndis_bind_config - add RNDIS network link to a configuration
+ * @c: the configuration to support the network link
+ * @ethaddr: a buffer in which the ethernet address of the host side
+ * side of the link was recorded
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gether_setup(). Caller is also responsible
+ * for calling @gether_cleanup() before module unload.
+ */
+static inline int rndis_bind_config(struct usb_configuration *c,
+ u8 ethaddr[ETH_ALEN])
+{
+ return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+}
+
+
#endif /* __U_ETHER_H */
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 4ddb279cfb35..095447d9e3a2 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -23,12 +23,16 @@
#include <mach/usb_phy.h>
#include <mach/iomap.h>
+#include "../../../arch/arm/mach-tegra/tegra_usb_phy.h"
+
#if 0
#define EHCI_DBG(stuff...) pr_info("ehci-tegra: " stuff)
#else
#define EHCI_DBG(stuff...) do {} while (0)
#endif
+#define TEGRA_USB_PORTSC1_PFSC (1 << 24)
+
static const char driver_name[] = "tegra-ehci";
#define TEGRA_USB_DMA_ALIGN 32
@@ -51,6 +55,22 @@ struct dma_align_buffer {
u8 data[0];
};
+#ifdef CONFIG_MACH_COLIBRI_T20
+/* To limit the speed of USB to full speed */
+int g_usb_high_speed = 0;
+
+/* To limit the speed of USB to full speed */
+static int __init enable_usb_high_speed(char *s)
+{
+ if (!(*s) || !strcmp(s, "1"))
+ g_usb_high_speed = 1;
+
+ return 0;
+}
+__setup("usb_high_speed=", enable_usb_high_speed);
+EXPORT_SYMBOL_GPL(g_usb_high_speed);
+#endif /* CONFIG_MACH_COLIBRI_T20 */
+
static void free_align_buffer(struct urb *urb)
{
struct dma_align_buffer *temp = container_of(urb->transfer_buffer,
@@ -186,6 +206,71 @@ static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd)
return irq_status;
}
+static int tegra_ehci_internal_port_reset(
+ struct ehci_hcd *ehci,
+ u32 __iomem *portsc_reg
+)
+{
+ u32 temp;
+ unsigned long flags;
+ int retval = 0;
+ int i, tries;
+ u32 saved_usbintr;
+
+ spin_lock_irqsave(&ehci->lock, flags);
+ saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable);
+ /* disable USB interrupt */
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+
+ /*
+ * Here we have to do Port Reset at most twice for
+ * Port Enable bit to be set.
+ */
+ for (i = 0; i < 2; i++) {
+ temp = ehci_readl(ehci, portsc_reg);
+ temp |= PORT_RESET;
+ ehci_writel(ehci, temp, portsc_reg);
+ mdelay(10);
+ temp &= ~PORT_RESET;
+ ehci_writel(ehci, temp, portsc_reg);
+ mdelay(1);
+ tries = 100;
+ do {
+ mdelay(1);
+ /*
+ * Up to this point, Port Enable bit is
+ * expected to be set after 2 ms waiting.
+ * USB1 usually takes extra 45 ms, for safety,
+ * we take 100 ms as timeout.
+ */
+ temp = ehci_readl(ehci, portsc_reg);
+ } while (!(temp & PORT_PE) && tries--);
+ if (temp & PORT_PE)
+ break;
+ }
+ if (i == 2)
+ retval = -ETIMEDOUT;
+
+ /*
+ * Clear Connect Status Change bit if it's set.
+ * We can't clear PORT_PEC. It will also cause PORT_PE to be cleared.
+ */
+ if (temp & PORT_CSC)
+ ehci_writel(ehci, PORT_CSC, portsc_reg);
+
+ /*
+ * Write to clear any interrupt status bits that might be set
+ * during port reset.
+ */
+ temp = ehci_readl(ehci, &ehci->regs->status);
+ ehci_writel(ehci, temp, &ehci->regs->status);
+
+ /* restore original interrupt enable bits */
+ ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable);
+
+ return retval;
+}
static int tegra_ehci_hub_control(
struct usb_hcd *hcd,
@@ -201,6 +286,29 @@ static int tegra_ehci_hub_control(
int retval = 0;
u32 __iomem *status_reg;
+#ifdef CONFIG_MACH_COLIBRI_T20
+ u32 temp;
+
+ /* To limit the speed of USB to full speed */
+ if (!g_usb_high_speed) {
+ /* Check whether port is not 2nd one internally connected to
+ ASIX Ethernet chip, set PFSC (Port Force Full Speed) only
+ for externally accessible OTG and host port */
+ if (tegra->phy->inst != 1) {
+ status_reg = &ehci->regs->port_status[(wIndex & 0xff)
+ - 1];
+ temp = ehci_readl(ehci, status_reg);
+ /* Check whether PFSC bit is already set or not */
+ if (!(temp & TEGRA_USB_PORTSC1_PFSC)) {
+ ehci_writel(ehci, (temp |
+ TEGRA_USB_PORTSC1_PFSC),
+ status_reg);
+ temp = ehci_readl(ehci, status_reg);
+ }
+ }
+ }
+#endif /* CONFIG_MACH_COLIBRI_T20 */
+
if (!tegra_usb_phy_hw_accessible(tegra->phy)) {
if (buf)
memset(buf, 0, wLength);
@@ -249,6 +357,13 @@ static int tegra_ehci_hub_control(
break;
}
+ /* For USB1 port we need to issue Port Reset twice internally */
+ if (tegra->phy->inst == 0 &&
+ (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) {
+ status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
+ return tegra_ehci_internal_port_reset(ehci, status_reg);
+ }
+
/* handle ehci hub control request */
retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index bcb3e8680337..e38d2b4ca134 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -25,6 +25,14 @@ if USB || USB_GADGET
#
# USB Transceiver Drivers
#
+config USB_COLIBRI_OTG
+ boolean "Colibri OTG Driver"
+ depends on USB && ARCH_TEGRA && !USB_TEGRA_OTG
+ select USB_OTG_UTILS
+ help
+ Enable this driver on boards which use a regular GPIO for VBUS
+ detection.
+
config USB_GPIO_VBUS
tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
depends on GENERIC_GPIO
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index 0ef95e45a583..cbedff4e254f 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg_id.o
# transceiver drivers
obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
+obj-$(CONFIG_USB_COLIBRI_OTG) += colibri-otg.o
CFLAGS_tegra-otg.o = -Werror
obj-$(CONFIG_USB_TEGRA_OTG) += tegra-otg.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
diff --git a/drivers/usb/otg/colibri-otg.c b/drivers/usb/otg/colibri-otg.c
new file mode 100644
index 000000000000..54d792536363
--- /dev/null
+++ b/drivers/usb/otg/colibri-otg.c
@@ -0,0 +1,268 @@
+/*
+ * drivers/usb/otg/colibri-otg.c
+ *
+ * OTG transceiver driver for Tegra UTMI phy with GPIO VBUS detection
+ *
+ * Copyright (C) 2010 NVIDIA Corp.
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2012 Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/colibri_usb.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
+
+#include <mach/gpio.h>
+
+struct colibri_otg_data {
+ struct otg_transceiver otg;
+ spinlock_t lock;
+ int irq;
+ struct platform_device *host;
+ struct platform_device *pdev;
+ struct work_struct work;
+};
+
+static const char *tegra_state_name(enum usb_otg_state state)
+{
+ if (state == OTG_STATE_A_HOST)
+ return "HOST";
+ if (state == OTG_STATE_B_PERIPHERAL)
+ return "PERIPHERAL";
+ if (state == OTG_STATE_A_SUSPEND)
+ return "SUSPEND";
+ return "INVALID";
+}
+
+void tegra_start_host(struct colibri_otg_data *tegra)
+{
+ struct colibri_otg_platform_data *pdata = tegra->otg.dev->platform_data;
+ if (!tegra->pdev) {
+ tegra->pdev = pdata->host_register();
+ }
+}
+
+void tegra_stop_host(struct colibri_otg_data *tegra)
+{
+ struct colibri_otg_platform_data *pdata = tegra->otg.dev->platform_data;
+ if (tegra->pdev) {
+ pdata->host_unregister(tegra->pdev);
+ tegra->pdev = NULL;
+ }
+}
+
+static void tegra_otg_notify_event(struct otg_transceiver *otg,
+ enum usb_xceiv_events event)
+{
+ otg->last_event = event;
+ atomic_notifier_call_chain(&otg->notifier, event, NULL);
+}
+
+static void irq_work(struct work_struct *work)
+{
+ struct colibri_otg_data *tegra =
+ container_of(work, struct colibri_otg_data, work);
+ struct otg_transceiver *otg = &tegra->otg;
+ enum usb_otg_state from = otg->state;
+ enum usb_otg_state to = OTG_STATE_UNDEFINED;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tegra->lock, flags);
+
+ /* Check client detect (High active) */
+ mdelay(100);
+ if (gpio_get_value(irq_to_gpio(tegra->irq)))
+ to = OTG_STATE_B_PERIPHERAL;
+ else
+ to = OTG_STATE_A_HOST;
+
+ spin_unlock_irqrestore(&tegra->lock, flags);
+
+ if (to != OTG_STATE_UNDEFINED) {
+ otg->state = to;
+
+ if (from != to) {
+ dev_info(tegra->otg.dev, "%s --> %s\n",
+ tegra_state_name(from), tegra_state_name(to));
+
+ if (to == OTG_STATE_B_PERIPHERAL) {
+ if (from == OTG_STATE_A_HOST) {
+ tegra_stop_host(tegra);
+ tegra_otg_notify_event(otg, USB_EVENT_NONE);
+ }
+ if (otg->gadget) {
+ usb_gadget_vbus_connect(otg->gadget);
+ tegra_otg_notify_event(otg, USB_EVENT_VBUS);
+ }
+ } else if (to == OTG_STATE_A_HOST) {
+ if (otg->gadget && (from == OTG_STATE_B_PERIPHERAL)) {
+ usb_gadget_vbus_disconnect(otg->gadget);
+ tegra_otg_notify_event(otg, USB_EVENT_NONE);
+ }
+ tegra_start_host(tegra);
+ tegra_otg_notify_event(otg, USB_EVENT_ID);
+ }
+ }
+ }
+}
+
+static irqreturn_t colibri_otg_irq(int irq, void *data)
+{
+ struct colibri_otg_data *tegra = data;
+
+ schedule_work(&tegra->work);
+
+ return IRQ_HANDLED;
+}
+
+static int colibri_otg_set_peripheral(struct otg_transceiver *otg,
+ struct usb_gadget *gadget)
+{
+ struct colibri_otg_data *tegra;
+
+ tegra = container_of(otg, struct colibri_otg_data, otg);
+ otg->gadget = gadget;
+
+ /* Set initial state */
+ schedule_work(&tegra->work);
+
+ return 0;
+}
+
+static int colibri_otg_set_host(struct otg_transceiver *otg,
+ struct usb_bus *host)
+{
+ struct colibri_otg_data *tegra;
+
+ tegra = container_of(otg, struct colibri_otg_data, otg);
+ otg->host = host;
+
+ return 0;
+}
+
+static int colibri_otg_set_power(struct otg_transceiver *otg, unsigned mA)
+{
+ return 0;
+}
+
+static int colibri_otg_set_suspend(struct otg_transceiver *otg, int suspend)
+{
+ return 0;
+}
+
+static int colibri_otg_probe(struct platform_device *pdev)
+{
+ struct colibri_otg_data *tegra;
+ struct colibri_otg_platform_data *plat = pdev->dev.platform_data;
+ int err, gpio_cd;
+
+ if (!plat) {
+ dev_err(&pdev->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ tegra = kzalloc(sizeof(struct colibri_otg_data), GFP_KERNEL);
+ if (!tegra)
+ return -ENOMEM;
+
+ tegra->otg.dev = &pdev->dev;
+ tegra->otg.label = "colibri-otg";
+ tegra->otg.state = OTG_STATE_UNDEFINED;
+ tegra->otg.set_host = colibri_otg_set_host;
+ tegra->otg.set_peripheral = colibri_otg_set_peripheral;
+ tegra->otg.set_suspend = colibri_otg_set_suspend;
+ tegra->otg.set_power = colibri_otg_set_power;
+ spin_lock_init(&tegra->lock);
+
+ platform_set_drvdata(pdev, tegra);
+
+ tegra->otg.state = OTG_STATE_A_SUSPEND;
+
+ err = otg_set_transceiver(&tegra->otg);
+ if (err) {
+ dev_err(&pdev->dev, "can't register transceiver (%d)\n", err);
+ goto err_otg;
+ }
+
+ gpio_cd = plat->cable_detect_gpio;
+ err = gpio_request(gpio_cd, "USBC_DET");
+ if (err)
+ goto err_gpio;
+ gpio_direction_input(gpio_cd);
+
+ tegra->irq = gpio_to_irq(gpio_cd);
+ err = request_threaded_irq(tegra->irq, colibri_otg_irq, NULL,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "colibri-otg USBC_DET", tegra);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register USB client detect IRQ\n");
+ goto err_irq;
+ }
+
+ INIT_WORK (&tegra->work, irq_work);
+
+ dev_info(&pdev->dev, "otg transceiver registered\n");
+
+ return 0;
+
+err_irq:
+ gpio_free(gpio_cd);
+err_gpio:
+ otg_set_transceiver(NULL);
+err_otg:
+ platform_set_drvdata(pdev, NULL);
+ kfree(tegra);
+ return err;
+}
+
+static int __exit colibri_otg_remove(struct platform_device *pdev)
+{
+ struct colibri_otg_data *tegra = platform_get_drvdata(pdev);
+
+ free_irq(tegra->irq, tegra);
+ gpio_free(irq_to_gpio(tegra->irq));
+ otg_set_transceiver(NULL);
+ platform_set_drvdata(pdev, NULL);
+ kfree(tegra);
+
+ return 0;
+}
+
+static struct platform_driver colibri_otg_driver = {
+ .driver = {
+ .name = "colibri-otg",
+ },
+ .remove = __exit_p(colibri_otg_remove),
+ .probe = colibri_otg_probe,
+};
+
+static int __init colibri_otg_init(void)
+{
+ return platform_driver_register(&colibri_otg_driver);
+}
+subsys_initcall(colibri_otg_init);
+
+static void __exit colibri_otg_exit(void)
+{
+ platform_driver_unregister(&colibri_otg_driver);
+}
+module_exit(colibri_otg_exit);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 2a9ed6ec8cb7..ea4e5ebdd35a 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -231,9 +231,11 @@ static void option_instat_callback(struct urb *urb);
#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001
+#define NOVATELWIRELESS_PRODUCT_E362 0x9010
#define NOVATELWIRELESS_PRODUCT_G1 0xA001
#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002
#define NOVATELWIRELESS_PRODUCT_G2 0xA010
+#define NOVATELWIRELESS_PRODUCT_MC551 0xB001
/* AMOI PRODUCTS */
#define AMOI_VENDOR_ID 0x1614
@@ -265,6 +267,9 @@ static void option_instat_callback(struct urb *urb);
#define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181
#define DELL_PRODUCT_5730_MINICARD_VZW 0x8182
+#define DELL_PRODUCT_5800_MINICARD_VZW 0x8195 /* Novatel E362 */
+#define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */
+
#define KYOCERA_VENDOR_ID 0x0c88
#define KYOCERA_PRODUCT_KPC650 0x17da
#define KYOCERA_PRODUCT_KPC680 0x180a
@@ -715,6 +720,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) },
+ /* Novatel Ovation MC551 a.k.a. Verizon USB551L */
+ { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) },
@@ -737,6 +745,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_SPRINT) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_TELUS) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */
+ { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index 39ac49e0682c..7fce1987ddc7 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -82,4 +82,8 @@ config LOGO_M32R_CLUT224
depends on M32R
default y
+config LOGO_CUSTOM_CLUT224
+ bool "Custom 224-color Linux logo"
+ default n
+
endif # LOGO
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
index 3b437813584c..45d4b5346d07 100644
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o
obj-$(CONFIG_SPU_BASE) += logo_spe_clut224.o
+obj-$(CONFIG_LOGO_CUSTOM_CLUT224) += logo_custom_clut224.o
+
# How to generate logo's
# Use logo-cfiles to retrieve list of .c files to be built
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index ea7a8ccc830c..6e29415c9790 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -100,6 +100,10 @@ const struct linux_logo * __init_refok fb_find_logo(int depth)
/* M32R Linux logo */
logo = &logo_m32r_clut224;
#endif
+#ifdef CONFIG_LOGO_CUSTOM_CLUT224
+ /* Custom Linux logo */
+ logo = &logo_custom_clut224;
+#endif
}
return logo;
}
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index bfd916e0e16e..d4c3f8bc9a49 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -1067,9 +1067,11 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status)
queue_work(system_freezable_wq, &dc->vblank_work);
if (status & FRAME_END_INT) {
+#ifndef CONFIG_ANDROID
struct timespec tm = CURRENT_TIME;
dc->frame_end_timestamp = timespec_to_ns(&tm);
wake_up(&dc->timestamp_wq);
+#endif /* !CONFIG_ANDROID */
/* Mark the frame_end as complete. */
if (!completion_done(&dc->frame_end_complete))
@@ -1079,6 +1081,7 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status)
}
}
+#ifndef CONFIG_ANDROID
/* XXX: Not sure if we limit look ahead to 1 frame */
bool tegra_dc_is_within_n_vsync(struct tegra_dc *dc, s64 ts)
{
@@ -1094,6 +1097,7 @@ bool tegra_dc_does_vsync_separate(struct tegra_dc *dc, s64 new_ts, s64 old_ts)
!= div_s64((old_ts - dc->frame_end_timestamp),
dc->frametime_ns)));
}
+#endif /* !CONFIG_ANDROID */
#endif
static irqreturn_t tegra_dc_irq(int irq, void *ptr)
@@ -1781,7 +1785,9 @@ static int tegra_dc_probe(struct nvhost_device *ndev,
mutex_init(&dc->one_shot_lock);
init_completion(&dc->frame_end_complete);
init_waitqueue_head(&dc->wq);
+#ifndef CONFIG_ANDROID
init_waitqueue_head(&dc->timestamp_wq);
+#endif /* !CONFIG_ANDROID */
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
INIT_WORK(&dc->reset_work, tegra_dc_reset_worker);
#endif
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 75c3a2a29658..e91071f70ddc 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -113,14 +113,18 @@ struct tegra_dc {
void *out_data;
struct tegra_dc_mode mode;
+#ifndef CONFIG_ANDROID
s64 frametime_ns;
+#endif /* !CONFIG_ANDROID */
struct tegra_dc_win windows[DC_N_WINDOWS];
struct tegra_dc_blend blend;
int n_windows;
wait_queue_head_t wq;
+#ifndef CONFIG_ANDROID
wait_queue_head_t timestamp_wq;
+#endif /* !CONFIG_ANDROID */
struct mutex lock;
struct mutex one_shot_lock;
@@ -165,7 +169,9 @@ struct tegra_dc {
struct delayed_work underflow_work;
u32 one_shot_delay_ms;
struct delayed_work one_shot_work;
+#ifndef CONFIG_ANDROID
s64 frame_end_timestamp;
+#endif /* !CONFIG_ANDROID */
};
#define print_mode_info(dc, mode) do { \
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 88273e26c51c..37a6d9bd3f80 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -56,7 +56,9 @@ struct tegra_dc_ext_flip_data {
struct tegra_dc_ext *ext;
struct work_struct work;
struct tegra_dc_ext_flip_win win[DC_N_WINDOWS];
+#ifndef CONFIG_ANDROID
struct list_head timestamp_node;
+#endif /* !CONFIG_ANDROID */
};
int tegra_dc_ext_get_num_outputs(void)
@@ -208,7 +210,9 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
{
int err = 0;
struct tegra_dc_ext_win *ext_win = &ext->win[win->idx];
+#ifndef CONFIG_ANDROID
s64 timestamp_ns;
+#endif /* !CONFIG_ANDROID */
if (flip_win->handle[TEGRA_DC_Y] == NULL) {
win->flags = 0;
@@ -272,6 +276,7 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
msecs_to_jiffies(500), NULL);
}
+#ifndef CONFIG_ANDROID
#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
timestamp_ns = timespec_to_ns(&flip_win->attr.timestamp);
@@ -286,9 +291,12 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
}
#endif
return err;
+#else /* !CONFIG_ANDROID */
+ return 0;
+#endif /* !CONFIG_ANDROID */
}
-static void (*flip_callback)(void);
+static int (*flip_callback)(void);
static spinlock_t flip_callback_lock;
static bool init_tegra_dc_flip_callback_called;
@@ -301,7 +309,7 @@ static int __init init_tegra_dc_flip_callback(void)
pure_initcall(init_tegra_dc_flip_callback);
-int tegra_dc_set_flip_callback(void (*callback)(void))
+int tegra_dc_set_flip_callback(int (*callback)(void))
{
WARN_ON(!init_tegra_dc_flip_callback_called);
@@ -337,11 +345,14 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
for (i = 0; i < DC_N_WINDOWS; i++) {
struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
- int j = 0, index = flip_win->attr.index;
+ int index = flip_win->attr.index;
struct tegra_dc_win *win;
struct tegra_dc_ext_win *ext_win;
+#ifndef CONFIG_ANDROID
+ int j = 0;
struct tegra_dc_ext_flip_data *temp = NULL;
s64 head_timestamp = 0;
+#endif /* !CONFIG_ANDROID */
if (index < 0)
continue;
@@ -353,6 +364,7 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
(flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR))
skip_flip = true;
+#ifndef CONFIG_ANDROID
mutex_lock(&ext_win->queue_lock);
list_for_each_entry(temp, &ext_win->timestamp_queue,
timestamp_node) {
@@ -377,6 +389,7 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
if (!list_empty(&ext_win->timestamp_queue))
list_del(&data->timestamp_node);
mutex_unlock(&ext_win->queue_lock);
+#endif /* !CONFIG_ANDROID */
if (win->flags & TEGRA_WIN_FLAG_ENABLED) {
int j;
@@ -409,6 +422,9 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
flip_callback();
spin_unlock(&flip_callback_lock);
}
+#ifdef CONFIG_ANDROID
+ }
+#endif /* CONFIG_ANDROID */
for (i = 0; i < DC_N_WINDOWS; i++) {
struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
@@ -420,7 +436,9 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
tegra_dc_incr_syncpt_min(ext->dc, index,
flip_win->syncpt_max);
}
+#ifndef CONFIG_ANDROID
}
+#endif /* !CONFIG_ANDROID */
/* unpin and deref previous front buffers */
for (i = 0; i < nr_unpin; i++) {
@@ -531,7 +549,9 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
struct tegra_dc_ext_flip_data *data;
int work_index = -1;
int i, ret = 0;
+#ifndef CONFIG_ANDROID
bool has_timestamp = false;
+#endif /* !CONFIG_ANDROID */
#ifdef CONFIG_ANDROID
int index_check[DC_N_WINDOWS] = {0, };
@@ -572,8 +592,10 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
int index = args->win[i].index;
memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr));
+#ifndef CONFIG_ANDROID
if (timespec_to_ns(&flip_win->attr.timestamp))
has_timestamp = true;
+#endif /* !CONFIG_ANDROID */
if (index < 0)
continue;
@@ -648,11 +670,13 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
ret = -EINVAL;
goto unlock;
}
+#ifndef CONFIG_ANDROID
if (has_timestamp) {
mutex_lock(&ext->win[work_index].queue_lock);
list_add_tail(&data->timestamp_node, &ext->win[work_index].timestamp_queue);
mutex_unlock(&ext->win[work_index].queue_lock);
}
+#endif /* !CONFIG_ANDROID */
queue_work(ext->win[work_index].flip_wq, &data->work);
unlock_windows_for_flip(user, args);
@@ -993,8 +1017,10 @@ static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext)
}
mutex_init(&win->lock);
+#ifndef CONFIG_ANDROID
mutex_init(&win->queue_lock);
INIT_LIST_HEAD(&win->timestamp_queue);
+#endif /* !CONFIG_ANDROID */
}
return 0;
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
index ef7361d1d933..7238e95e59db 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -59,9 +59,11 @@ struct tegra_dc_ext_win {
atomic_t nr_pending_flips;
+#ifndef CONFIG_ANDROID
struct mutex queue_lock;
struct list_head timestamp_queue;
+#endif /* !CONFIG_ANDROID */
};
struct tegra_dc_ext {
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
index 55d9163d4faf..225d48ab15ee 100644
--- a/drivers/video/tegra/dc/hdmi.c
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -1258,6 +1258,9 @@ static bool tegra_dc_hdmi_valid_asp_ratio(const struct tegra_dc *dc,
int m_aspratio = 0;
int s_aspratio = 0;
+ if (!mode->yres)
+ return false;
+
/* To check the aspect upto two decimal digits, calculate in % */
m_aspratio = (mode->xres*100 / mode->yres);
@@ -1345,7 +1348,8 @@ void tegra_dc_hdmi_detect_config(struct tegra_dc *dc,
hdmi->dvi = !(specs->misc & FB_MISC_HDMI);
- tegra_fb_update_monspecs(dc->fb, specs, tegra_dc_hdmi_mode_filter);
+ if (dc->fb != NULL)
+ tegra_fb_update_monspecs(dc->fb, specs, tegra_dc_hdmi_mode_filter);
#ifdef CONFIG_SWITCH
hdmi->hpd_switch.state = 0;
switch_set_state(&hdmi->hpd_switch, 1);
@@ -1413,11 +1417,18 @@ static bool tegra_dc_hdmi_detect(struct tegra_dc *dc)
struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
struct fb_monspecs specs;
int err;
+ int cnt = 0;
if (!tegra_dc_hdmi_hpd(dc))
goto fail;
err = tegra_edid_get_monspecs(hdmi->edid, &specs);
+ /* retry, maybe hdmi detect is not debounced or the monitor needs some time */
+ while ( (err < 0) && (cnt++ < 4) ) {
+ dev_err(&dc->ndev->dev, "error reading edid, trying again in 500ms\n");
+ msleep(500);
+ err = tegra_edid_get_monspecs(hdmi->edid, &specs);
+ }
if (err < 0) {
if (dc->out->n_modes)
tegra_dc_enable(dc);
diff --git a/drivers/video/tegra/dc/mode.c b/drivers/video/tegra/dc/mode.c
index 3a95f2e7ab0e..f5cd4fb0cdea 100644
--- a/drivers/video/tegra/dc/mode.c
+++ b/drivers/video/tegra/dc/mode.c
@@ -26,6 +26,179 @@
#include "dc_reg.h"
#include "dc_priv.h"
+const struct fb_videomode tegra_modes[] = {
+ /* EDT 5.7" ET070080DH or TouchRevolution Fusion 7" */
+ {
+ .name = "800x480",
+ .refresh = 60,
+ .xres = 800,
+ .yres = 480,
+ .pixclock = 30807,
+ .left_margin = 128,
+ .right_margin = 64,
+ .upper_margin = 22,
+ .lower_margin = 20,
+ .hsync_len = 64,
+ .vsync_len = 3,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .flag = FB_FLAG_RATIO_16_9,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ /* TouchRevolution Fusion 10" aka Chunghwa Picture Tubes
+ * CLAA100NC05 10.1 inch 1024x600 single channel LVDS panel
+ */
+ {
+ .name = "1024x600",
+ .refresh = 60,
+ .xres = 1024,
+ .yres = 600,
+ .pixclock = KHZ2PICOS(48000),
+ .left_margin = 104,
+ .right_margin = 43,
+ .upper_margin = 24,
+ .lower_margin = 20,
+ .hsync_len = 5,
+ .vsync_len = 5,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .flag = FB_FLAG_RATIO_16_9,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ /* 1366x768 */
+ .refresh = 60,
+ .xres = 1366,
+ .yres = 768,
+ .pixclock = KHZ2PICOS(72072),
+ .hsync_len = 58, /* h_sync_width */
+ .vsync_len = 4, /* v_sync_width */
+ .left_margin = 58, /* h_back_porch */
+ .upper_margin = 4, /* v_back_porch */
+ .right_margin = 58, /* h_front_porch */
+ .lower_margin = 4, /* v_front_porch */
+ .vmode = FB_VMODE_NONINTERLACED,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ },
+ {
+ /* 1680x1050p 59.94/60hz */
+ .refresh = 60,
+ .xres = 1680,
+ .yres = 1050,
+ .pixclock = KHZ2PICOS(147140),
+ .hsync_len = 184, /* h_sync_width */
+ .vsync_len = 3, /* v_sync_width */
+ .left_margin = 288, /* h_back_porch */
+ .upper_margin = 33, /* v_back_porch */
+ .right_margin = 104, /* h_front_porch */
+ .lower_margin = 1, /* v_front_porch */
+ .vmode = FB_VMODE_NONINTERLACED,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ },
+ {
+ /* 1920x1080p 59.94/60hz CVT */
+ .refresh = 60,
+ .xres = 1920,
+ .yres = 1080,
+ .pixclock = KHZ2PICOS(148500),
+ .hsync_len = 44, /* h_sync_width */
+ .vsync_len = 5, /* v_sync_width */
+ .left_margin = 148, /* h_back_porch */
+ .upper_margin = 36, /* v_back_porch */
+ .right_margin = 88, /* h_front_porch */
+ .lower_margin = 4, /* v_front_porch */
+ .vmode = FB_VMODE_NONINTERLACED,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ },
+ {
+ /* 1920x1200p 60hz */
+ .refresh = 60,
+ .xres = 1920,
+ .yres = 1200,
+ .pixclock = KHZ2PICOS(154000),
+ .hsync_len = 32, /* h_sync_width */
+ .vsync_len = 6, /* v_sync_width */
+ .left_margin = 80, /* h_back_porch */
+ .upper_margin = 26, /* v_back_porch */
+ .right_margin = 48, /* h_front_porch */
+ .lower_margin = 3, /* v_front_porch */
+ .vmode = FB_VMODE_NONINTERLACED,
+ .sync = 0,
+ },
+ /* Portrait modes */
+ {
+ .name = "480x640",
+ .refresh = 60,
+ .xres = 480,
+ .yres = 640,
+ .pixclock = 55555,
+ .left_margin = 20,
+ .right_margin = 8,
+ .upper_margin = 7,
+ .lower_margin = 8,
+ .hsync_len = 4,
+ .vsync_len = 1,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "540x960",
+ .refresh = 60,
+ .xres = 540,
+ .yres = 960,
+ .pixclock = 100000,
+ .left_margin = 32,
+ .right_margin = 32,
+ .upper_margin = 1,
+ .lower_margin = 2,
+ .hsync_len = 16,
+ .vsync_len = 1,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+ {
+ .name = "720x1280",
+ .refresh = 60,
+ .xres = 720,
+ .yres = 1280,
+ .pixclock = 16282,
+ .left_margin = 100,
+ .right_margin = 4,
+ .upper_margin = 14,
+ .lower_margin = 4,
+ .hsync_len = 4,
+ .vsync_len = 4,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED
+ },
+};
+
+/* try to find best matching mode using our modes, VESA and CEA modes from
+ * modedb
+ */
+int tegra_fb_find_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+ const char* option, unsigned int default_bpp)
+{
+ int out;
+
+ out = fb_find_mode(var, info, option, tegra_modes,
+ ARRAY_SIZE(tegra_modes), NULL, default_bpp);
+
+ /* Only accept this mode if we found a reasonable match (resolution) */
+ if (out == 1 || out == 2)
+ return out;
+
+ out = fb_find_mode(&info->var, info, option,
+ cea_modes, CEA_MODEDB_SIZE, NULL, default_bpp);
+
+ /* Check if we found a full match */
+ if (out == 1 || out == 2)
+ return out;
+
+ return fb_find_mode(&info->var, info, option,
+ vesa_modes, VESA_MODEDB_SIZE, NULL, default_bpp);
+}
+EXPORT_SYMBOL(tegra_fb_find_mode);
+
+
/* return non-zero if constraint is violated */
static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href)
{
@@ -137,6 +310,7 @@ static bool check_ref_to_sync(struct tegra_dc_mode *mode)
return true;
}
+#ifndef CONFIG_ANDROID
static s64 calc_frametime_ns(const struct tegra_dc_mode *m)
{
long h_total, v_total;
@@ -147,6 +321,7 @@ static s64 calc_frametime_ns(const struct tegra_dc_mode *m)
return (!m->pclk) ? 0 : (s64)(div_s64(((s64)h_total * v_total *
1000000000ULL), m->pclk));
}
+#endif /* !CONFIG_ANDROID */
/* return in 1000ths of a Hertz */
int tegra_dc_calc_refresh(const struct tegra_dc_mode *m)
@@ -270,21 +445,108 @@ int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
{
memcpy(&dc->mode, mode, sizeof(dc->mode));
+ dev_info(&dc->ndev->dev, "using mode %dx%d pclk=%d href=%d vref=%d\n",
+ mode->h_active, mode->v_active, mode->pclk,
+ mode->h_ref_to_sync, mode->v_ref_to_sync
+ );
+
if (dc->out->type == TEGRA_DC_OUT_RGB)
panel_sync_rate = tegra_dc_calc_refresh(mode);
else if (dc->out->type == TEGRA_DC_OUT_DSI)
panel_sync_rate = dc->out->dsi->rated_refresh_rate * 1000;
print_mode(dc, mode, __func__);
+#ifndef CONFIG_ANDROID
dc->frametime_ns = calc_frametime_ns(mode);
+#endif /* !CONFIG_ANDROID */
return 0;
}
EXPORT_SYMBOL(tegra_dc_set_mode);
+int tegra_dc_var_to_dc_mode(struct tegra_dc *dc, struct fb_var_screeninfo *var,
+ struct tegra_dc_mode *mode)
+{
+ bool stereo_mode = false;
+ int err;
+
+ if (!var->pixclock)
+ return -EINVAL;
+
+ mode->pclk = PICOS2KHZ(var->pixclock) * 1000;
+ mode->h_sync_width = var->hsync_len;
+ mode->v_sync_width = var->vsync_len;
+ mode->h_back_porch = var->left_margin;
+ mode->v_back_porch = var->upper_margin;
+ mode->h_active = var->xres;
+ mode->v_active = var->yres;
+ mode->h_front_porch = var->right_margin;
+ mode->v_front_porch = var->lower_margin;
+ mode->stereo_mode = stereo_mode;
+
+ /*
+ * HACK:
+ * If v_front_porch is only 1, we would violate Constraint 5/6
+ * in this case, increase front porch by 1
+ */
+ if (mode->v_front_porch <= 1)
+ mode->v_front_porch = 2;
+
+
+ if (dc->out->type == TEGRA_DC_OUT_HDMI) {
+ /* HDMI controller requires h_ref=1, v_ref=1 */
+ mode->h_ref_to_sync = 1;
+ mode->v_ref_to_sync = 1;
+ } else {
+ /* Calculate ref_to_sync signals */
+ err = calc_ref_to_sync(mode);
+ if (err) {
+ dev_err(&dc->ndev->dev, "display timing ref_to_sync"
+ "calculation failed with code %d\n", err);
+ return -EINVAL;
+ }
+ dev_info(&dc->ndev->dev, "Calculated sync href=%d vref=%d\n",
+ mode->h_ref_to_sync, mode->v_ref_to_sync);
+ }
+ if (!check_ref_to_sync(mode)) {
+ dev_err(&dc->ndev->dev,
+ "display timing doesn't meet restrictions.\n");
+ return -EINVAL;
+ }
+
+#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
+ /* Double the pixel clock and update v_active only for
+ * frame packed mode */
+ if (mode->stereo_mode) {
+ mode->pclk *= 2;
+ /* total v_active = yres*2 + activespace */
+ mode->v_active = var->yres * 2 +
+ var->vsync_len +
+ var->upper_margin +
+ var->lower_margin;
+ }
+#endif
+
+ mode->flags = 0;
+
+ if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
+ mode->flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
+
+ if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
+ mode->flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_var_to_dc_mode);
+
+/*
+ * This method is only used by sysfs interface
+ * /sys/devices/tegradc.1/nvdps
+ */
int tegra_dc_set_fb_mode(struct tegra_dc *dc,
const struct fb_videomode *fbmode, bool stereo_mode)
{
+ int err;
struct tegra_dc_mode mode;
if (!fbmode->pixclock)
@@ -305,17 +567,28 @@ int tegra_dc_set_fb_mode(struct tegra_dc *dc,
mode.h_ref_to_sync = 1;
mode.v_ref_to_sync = 1;
} else {
- calc_ref_to_sync(&mode);
+ /*
+ * HACK:
+ * If v_front_porch is only 1, we would violate Constraint 5/6
+ * in this case, increase front porch by 1
+ */
+ if (mode.v_front_porch <= 1)
+ mode.v_front_porch = 2;
+
+ err = calc_ref_to_sync(&mode);
+ if (err) {
+ dev_err(&dc->ndev->dev, "display timing ref_to_sync"
+ "calculation failed with code %d\n", err);
+ return -EINVAL;
+ }
+ dev_info(&dc->ndev->dev, "Calculated sync href=%d vref=%d\n",
+ mode.h_ref_to_sync, mode.v_ref_to_sync);
}
if (!check_ref_to_sync(&mode)) {
dev_err(&dc->ndev->dev,
- "Display timing doesn't meet restrictions.\n");
+ "display timing doesn't meet restrictions.\n");
return -EINVAL;
}
- dev_info(&dc->ndev->dev, "Using mode %dx%d pclk=%d href=%d vref=%d\n",
- mode.h_active, mode.v_active, mode.pclk,
- mode.h_ref_to_sync, mode.v_ref_to_sync
- );
#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
/* Double the pixel clock and update v_active only for
diff --git a/drivers/video/tegra/dc/nvhdcp.c b/drivers/video/tegra/dc/nvhdcp.c
index 3566e2bd33b5..8489ebf69719 100644
--- a/drivers/video/tegra/dc/nvhdcp.c
+++ b/drivers/video/tegra/dc/nvhdcp.c
@@ -760,7 +760,7 @@ static int get_repeater_info(struct tegra_nvhdcp *nvhdcp)
{
int e, retries;
u8 b_caps;
- u16 b_status;
+ u16 b_status = 0;
nvhdcp_vdbg("repeater found:fetching repeater info\n");
diff --git a/drivers/video/tegra/dc/window.c b/drivers/video/tegra/dc/window.c
index cd91fab428ed..af18564f45b9 100644
--- a/drivers/video/tegra/dc/window.c
+++ b/drivers/video/tegra/dc/window.c
@@ -24,7 +24,9 @@
#include "dc_priv.h"
static int no_vsync;
+#ifndef CONFIG_ANDROID
static atomic_t frame_end_ref = ATOMIC_INIT(0);
+#endif /* !CONFIG_ANDROID */
module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR);
@@ -41,6 +43,7 @@ static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
return true;
}
+#ifndef CONFIG_ANDROID
int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable)
{
tegra_dc_writel(dc, FRAME_END_INT, DC_CMD_INT_STATUS);
@@ -51,6 +54,7 @@ int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable)
tegra_dc_mask_interrupt(dc, FRAME_END_INT);
return 0;
}
+#endif /* !CONFIG_ANDROID */
static int get_topmost_window(u32 *depths, unsigned long *wins)
{
@@ -418,9 +422,14 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
} else {
clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count);
- tegra_dc_mask_interrupt(dc, V_BLANK_INT | ALL_UF_INT);
+ tegra_dc_mask_interrupt(dc,
+#ifndef CONFIG_ANDROID
+ V_BLANK_INT | ALL_UF_INT);
if (!atomic_read(&frame_end_ref))
tegra_dc_mask_interrupt(dc, FRAME_END_INT);
+#else /* !CONFIG_ANDROID */
+ FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
+#endif /* !CONFIG_ANDROID */
}
if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
@@ -470,7 +479,11 @@ void tegra_dc_trigger_windows(struct tegra_dc *dc)
if (!dirty) {
if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+#ifndef CONFIG_ANDROID
&& !atomic_read(&frame_end_ref))
+#else /* !CONFIG_ANDROID */
+ )
+#endif /* !CONFIG_ANDROID */
tegra_dc_mask_interrupt(dc, FRAME_END_INT);
}
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index f69048f62cc2..b7aa066751fc 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -55,9 +55,6 @@ struct tegra_fb_info {
bool valid;
struct resource *fb_mem;
-
- int xres;
- int yres;
};
/* palette array used by the fbcon */
@@ -75,10 +72,18 @@ static int tegra_fb_check_var(struct fb_var_screeninfo *var,
info->screen_size)
return -EINVAL;
+ fb_var_to_videomode(&mode, var);
+
+#if defined(CONFIG_MACH_APALIS_T30) || defined(CONFIG_MACH_COLIBRI_T20) || \
+defined(CONFIG_MACH_COLIBRI_T30)
+ /* Hack: avoid 24 Hz mode in X resulting in no display at all */
+ if (mode.refresh < 50)
+ return -EINVAL;
+#endif /* CONFIG_MACH_APALIS_T30 | CONFIG_MACH_COLIBRI_T20 |
+ CONFIG_MACH_COLIBRI_T30 */
+
/* Apply mode filter for HDMI only -LVDS supports only fix mode */
if (ops && ops->mode_filter) {
-
- fb_var_to_videomode(&mode, var);
if (!ops->mode_filter(dc, &mode))
return -EINVAL;
@@ -87,8 +92,35 @@ static int tegra_fb_check_var(struct fb_var_screeninfo *var,
}
/* Double yres_virtual to allow double buffering through pan_display */
+ var->xres_virtual = var->xres;
var->yres_virtual = var->yres * 2;
+ /* we only support RGB ordering for now */
+ switch (var->bits_per_pixel) {
+ case 32:
+ case 24:
+ var->bits_per_pixel = 32;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ case 16:
+ default:
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ break;
+ }
+
return 0;
}
@@ -97,103 +129,61 @@ static int tegra_fb_set_par(struct fb_info *info)
struct tegra_fb_info *tegra_fb = info->par;
struct fb_var_screeninfo *var = &info->var;
struct tegra_dc *dc = tegra_fb->win->dc;
+ int err;
- if (var->bits_per_pixel) {
- /* we only support RGB ordering for now */
- switch (var->bits_per_pixel) {
- case 32:
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 16;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
- break;
- case 16:
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
- break;
-
- default:
- return -EINVAL;
- }
- /* if line_length unset, then pad the stride */
- info->fix.line_length = var->xres * var->bits_per_pixel / 8;
- info->fix.line_length = round_up(info->fix.line_length,
- TEGRA_LINEAR_PITCH_ALIGNMENT);
- tegra_fb->win->stride = info->fix.line_length;
- tegra_fb->win->stride_uv = 0;
- tegra_fb->win->phys_addr_u = 0;
- tegra_fb->win->phys_addr_v = 0;
- }
-
- if (var->pixclock) {
- bool stereo;
- unsigned old_len = 0;
- struct fb_videomode m;
- struct fb_videomode *old_mode = NULL;
-
- fb_var_to_videomode(&m, var);
+ struct tegra_dc_mode mode;
- /* Load framebuffer info with new mode details*/
- old_mode = info->mode;
- old_len = info->fix.line_length;
-
- info->mode = (struct fb_videomode *)
- fb_find_nearest_mode(&m, &info->modelist);
- if (!info->mode) {
- dev_warn(&tegra_fb->ndev->dev, "can't match video mode\n");
- info->mode = old_mode;
- return -EINVAL;
- }
+ /* This is usually altered to 16/32 by tegra_fb_check_var
+ * above which is called before this function
+ */
+ switch (var->bits_per_pixel) {
+ case 32:
+ tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
+ break;
+ case 16:
+ tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
- /* Update fix line_length and window stride as per new mode */
- info->fix.line_length = var->xres * var->bits_per_pixel / 8;
- info->fix.line_length = round_up(info->fix.line_length,
- TEGRA_LINEAR_PITCH_ALIGNMENT);
- tegra_fb->win->stride = info->fix.line_length;
+ /* if line_length unset, then pad the stride */
+ info->fix.line_length = var->xres * var->bits_per_pixel / 8;
+ info->fix.line_length = round_up(info->fix.line_length,
+ TEGRA_LINEAR_PITCH_ALIGNMENT);
+ tegra_fb->win->stride = info->fix.line_length;
+ tegra_fb->win->stride_uv = 0;
+ tegra_fb->win->phys_addr_u = 0;
+ tegra_fb->win->phys_addr_v = 0;
+
+ tegra_fb->win->w.full = dfixed_const(var->xres);
+ tegra_fb->win->h.full = dfixed_const(var->yres);
+ tegra_fb->win->out_w = var->xres;
+ tegra_fb->win->out_h = var->yres;
+
+ dev_info(&tegra_fb->ndev->dev, "switching framebuffer to %dx%d\n",
+ var->xres, var->yres);
+
+ err = tegra_dc_var_to_dc_mode(dc, var, &mode);
+ if (err) {
+ dev_warn(&tegra_fb->ndev->dev, "could not convert var %d\n", err);
+ return -EINVAL;
+ }
- /*
- * only enable stereo if the mode supports it and
- * client requests it
- */
- stereo = !!(var->vmode & info->mode->vmode &
-#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
- FB_VMODE_STEREO_FRAME_PACK);
-#else
- FB_VMODE_STEREO_LEFT_RIGHT);
-#endif
+ err = tegra_dc_set_mode(dc, &mode);
+ if (err) {
+ dev_warn(&tegra_fb->ndev->dev, "could not set dc mode %d\n", err);
+ return -EINVAL;
+ }
- /* Configure DC with new mode */
- if (tegra_dc_set_fb_mode(dc, info->mode, stereo)) {
- /* Error while configuring DC, fallback to old mode */
- dev_warn(&tegra_fb->ndev->dev, "can't configure dc with mode %ux%u\n",
- info->mode->xres, info->mode->yres);
- info->mode = old_mode;
- info->fix.line_length = old_len;
- tegra_fb->win->stride = old_len;
- return -EINVAL;
- }
+ /* Reflect changes on HW */
+ if (dc->enabled)
+ tegra_dc_disable(dc);
+ tegra_dc_enable(dc);
- /* Reflect mode chnage on DC HW */
- if (dc->enabled)
- tegra_dc_disable(dc);
- tegra_dc_enable(dc);
+ return err;
- tegra_fb->win->w.full = dfixed_const(info->mode->xres);
- tegra_fb->win->h.full = dfixed_const(info->mode->yres);
- tegra_fb->win->out_w = info->mode->xres;
- tegra_fb->win->out_h = info->mode->yres;
- }
- return 0;
}
static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
@@ -417,6 +407,9 @@ static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long
}
int tegra_fb_get_mode(struct tegra_dc *dc) {
+ /* Avoid error when reading sysfs */
+ if (dc->fb->info->mode == NULL)
+ return 0;
return dc->fb->info->mode->refresh;
}
@@ -532,13 +525,11 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
/* Prepare a mode db */
for (i = 0; i < specs->modedb_len; i++) {
if (info->fbops->fb_check_var) {
- struct fb_videomode m;
-
/* Call mode filter to check mode */
fb_videomode_to_var(&var, &specs->modedb[i]);
if (!(info->fbops->fb_check_var(&var, info))) {
- fb_var_to_videomode(&m, &var);
- fb_add_videomode(&m,
+ fb_var_to_videomode(&specs->modedb[i], &var);
+ fb_add_videomode(&specs->modedb[i],
&fb_info->info->modelist);
/* EDID stds recommend first detailed mode
to be applied as default,but if first mode
@@ -584,6 +575,106 @@ void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
mutex_unlock(&fb_info->info->lock);
}
+struct tegra_dc_out_pin dc_out_pins[4];
+
+
+static int parse_opt(struct tegra_dc_out *out, char *this_opt)
+{
+ if (!strncmp(this_opt, "hsync:", 6)) {
+ if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+ out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].pol =
+ TEGRA_DC_OUT_PIN_POL_LOW;
+ } else {
+ out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].pol =
+ TEGRA_DC_OUT_PIN_POL_HIGH;
+ }
+ return 0;
+ } else if (!strncmp(this_opt, "vsync:", 6)) {
+ if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+ out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].pol =
+ TEGRA_DC_OUT_PIN_POL_LOW;
+ } else {
+ out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].pol =
+ TEGRA_DC_OUT_PIN_POL_HIGH;
+ }
+ return 0;
+ } else if (!strncmp(this_opt, "outputen:", 9)) {
+ if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
+ out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].pol =
+ TEGRA_DC_OUT_PIN_POL_LOW;
+ } else {
+ out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].pol =
+ TEGRA_DC_OUT_PIN_POL_HIGH;
+ }
+ return 0;
+ } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
+ if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
+ out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].pol =
+ TEGRA_DC_OUT_PIN_POL_LOW;
+ } else {
+ out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].pol =
+ TEGRA_DC_OUT_PIN_POL_HIGH;
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+static void tegra_dc_copy_pin_modes(struct tegra_dc_out *out)
+{
+ int i;
+ struct tegra_dc_out_pin *def = out->out_pins;
+ int n_out_pins_default = out->n_out_pins;
+
+ /* Allocate memory for dynamic output pin configuration... */
+ out->n_out_pins = 4;
+ out->out_pins = kmalloc(sizeof(struct tegra_dc_out_pin) * out->n_out_pins,
+ GFP_KERNEL);
+
+ /* ...set fallback values, we use the pin enum as array index... */
+ out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].name = TEGRA_DC_OUT_PIN_DATA_ENABLE;
+ out->out_pins[TEGRA_DC_OUT_PIN_DATA_ENABLE].pol = TEGRA_DC_OUT_PIN_POL_HIGH;
+ out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].name = TEGRA_DC_OUT_PIN_H_SYNC;
+ out->out_pins[TEGRA_DC_OUT_PIN_H_SYNC].pol = TEGRA_DC_OUT_PIN_POL_LOW;
+ out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].name = TEGRA_DC_OUT_PIN_V_SYNC;
+ out->out_pins[TEGRA_DC_OUT_PIN_V_SYNC].pol = TEGRA_DC_OUT_PIN_POL_LOW;
+ out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK;
+ out->out_pins[TEGRA_DC_OUT_PIN_PIXEL_CLOCK].pol = TEGRA_DC_OUT_PIN_POL_LOW;
+
+ /* ... and copy the static default config from platform data */
+ for (i = 0; i < n_out_pins_default; i++)
+ out->out_pins[def[i].name].pol = def[i].pol;
+}
+
+static int tegra_parse_options(struct tegra_dc_out *out, struct fb_info *info,
+ char *option)
+{
+ char *this_opt;
+
+ /* This off option works perfectly for framebuffer
+ * device, however the tegra binary driver somehow
+ * has troubles to handle a missing fb0
+ * (then, dc1 gets remapped to fb0, which seems
+ * to be an issue for the binary driver)...
+ */
+ if (!strcmp(option, "off"))
+ return -ENODEV;
+
+ while ((this_opt = strsep(&option, ",")) != NULL) {
+ /* Parse driver specific arguments for RGB output */
+ if (out->type == TEGRA_DC_OUT_RGB) {
+ if (parse_opt(out, this_opt) == 0)
+ continue;
+ }
+
+ /* No valid driver specific argument, has to be mode */
+ if (!tegra_fb_find_mode(&info->var, info, this_opt, 16))
+ return -EINVAL;
+ }
+ return 0;
+}
+
struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
struct tegra_dc *dc,
struct tegra_fb_data *fb_data,
@@ -597,6 +688,9 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
unsigned long fb_phys = 0;
int ret = 0;
unsigned stride;
+ char *param_option = NULL;
+ char *option = NULL;
+ char driver[10];
win = tegra_dc_get_window(dc, fb_data->win);
if (!win) {
@@ -615,8 +709,6 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
tegra_fb->win = win;
tegra_fb->ndev = ndev;
tegra_fb->fb_mem = fb_mem;
- tegra_fb->xres = fb_data->xres;
- tegra_fb->yres = fb_data->yres;
if (fb_mem) {
fb_size = resource_size(fb_mem);
@@ -653,6 +745,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->var.xres_virtual = fb_data->xres;
info->var.yres_virtual = fb_data->yres * 2;
info->var.bits_per_pixel = fb_data->bits_per_pixel;
+
info->var.activate = FB_ACTIVATE_VBL;
info->var.height = tegra_dc_get_out_height(dc);
info->var.width = tegra_dc_get_out_width(dc);
@@ -665,11 +758,11 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->var.vsync_len = 0;
info->var.vmode = FB_VMODE_NONINTERLACED;
+ /* window settings */
win->x.full = dfixed_const(0);
win->y.full = dfixed_const(0);
win->w.full = dfixed_const(fb_data->xres);
win->h.full = dfixed_const(fb_data->yres);
- /* TODO: set to output res dc */
win->out_x = 0;
win->out_y = 0;
win->out_w = fb_data->xres;
@@ -683,6 +776,32 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
win->stride_uv = 0;
win->flags = TEGRA_WIN_FLAG_ENABLED;
+ /* Set/copy default pin modes, if output is RGB... */
+ if (dc->out->type == TEGRA_DC_OUT_RGB)
+ tegra_dc_copy_pin_modes(dc->out);
+
+ /* try to use kernel cmd line specified mode */
+ sprintf(driver, "tegrafb%d", ndev->id);
+ fb_get_options(driver, &param_option);
+ if (param_option != NULL) {
+ option = param_option;
+ dev_info(&ndev->dev, "use cmd options for %s: %s\n",
+ driver, option);
+ } else {
+ option = dc->out->default_mode;
+ dev_info(&ndev->dev, "use default mode for %s: %s\n",
+ driver, option);
+ }
+
+ if (option != NULL) {
+ ret = tegra_parse_options(dc->out, info, option);
+ if (ret < 0)
+ goto err_iounmap_fb;
+ }
+
+ /* Activate current settings (tegra_fb_find_mode has call
+ * tegra_fb_check_var already)
+ */
if (fb_mem)
tegra_fb_set_par(info);
@@ -701,26 +820,6 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
tegra_dc_sync_windows(&tegra_fb->win, 1);
}
- if (dc->mode.pclk > 1000) {
- struct tegra_dc_mode *mode = &dc->mode;
- struct fb_videomode vmode;
-
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- info->var.pixclock = KHZ2PICOS(mode->rated_pclk / 1000);
- else
- info->var.pixclock = KHZ2PICOS(mode->pclk / 1000);
- info->var.left_margin = mode->h_back_porch;
- info->var.right_margin = mode->h_front_porch;
- info->var.upper_margin = mode->v_back_porch;
- info->var.lower_margin = mode->v_front_porch;
- info->var.hsync_len = mode->h_sync_width;
- info->var.vsync_len = mode->v_sync_width;
-
- /* Keep info->var consistent with info->modelist. */
- fb_var_to_videomode(&vmode, &info->var);
- fb_add_videomode(&vmode, &info->modelist);
- }
-
return tegra_fb;
err_iounmap_fb:
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c
index 4614689ec37c..2b92a62cc0bc 100644
--- a/drivers/video/tegra/host/bus_client.c
+++ b/drivers/video/tegra/host/bus_client.c
@@ -611,6 +611,7 @@ fail:
nvhost_free_channel(ch);
return err;
}
+EXPORT_SYMBOL(nvhost_client_device_init);
int nvhost_client_device_suspend(struct nvhost_device *dev)
{
@@ -658,6 +659,7 @@ fail:
return -ENXIO;
}
+EXPORT_SYMBOL(nvhost_client_device_get_resources);
void nvhost_client_device_put_resources(struct nvhost_device *dev)
{
@@ -670,3 +672,4 @@ void nvhost_client_device_put_resources(struct nvhost_device *dev)
release_mem_region(r->start, resource_size(r));
}
+EXPORT_SYMBOL(nvhost_client_device_put_resources);
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index 5bde55ad2ff5..f22c91ac03f1 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -639,8 +639,10 @@ void nvhost_module_busy_ext(struct nvhost_device *dev)
{
nvhost_module_busy(dev);
}
+EXPORT_SYMBOL(nvhost_module_busy_ext);
void nvhost_module_idle_ext(struct nvhost_device *dev)
{
nvhost_module_idle(dev);
}
+EXPORT_SYMBOL(nvhost_module_idle_ext);
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index 38c28ca116e7..de3e04f65cdd 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -493,12 +493,14 @@ void nvhost_syncpt_cpu_incr_ext(struct nvhost_device *dev, u32 id)
struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt);
nvhost_syncpt_cpu_incr(sp, id);
}
+EXPORT_SYMBOL(nvhost_syncpt_cpu_incr_ext);
u32 nvhost_syncpt_read_ext(struct nvhost_device *dev, u32 id)
{
struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt);
return nvhost_syncpt_read(sp, id);
}
+EXPORT_SYMBOL(nvhost_syncpt_read_ext);
int nvhost_syncpt_wait_timeout_ext(struct nvhost_device *dev, u32 id, u32 thresh,
u32 timeout, u32 *value)
@@ -506,3 +508,4 @@ int nvhost_syncpt_wait_timeout_ext(struct nvhost_device *dev, u32 id, u32 thresh
struct nvhost_syncpt *sp = &(nvhost_get_host(dev)->syncpt);
return nvhost_syncpt_wait_timeout(sp, id, thresh, timeout, value);
}
+EXPORT_SYMBOL(nvhost_syncpt_wait_timeout_ext);
diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c
index 19b821d41284..e66ca982f2f3 100644
--- a/drivers/video/tegra/nvmap/nvmap.c
+++ b/drivers/video/tegra/nvmap/nvmap.c
@@ -387,6 +387,7 @@ phys_addr_t nvmap_pin(struct nvmap_client *client,
return ret ?: phys;
}
+EXPORT_SYMBOL(nvmap_pin);
phys_addr_t nvmap_handle_address(struct nvmap_client *c, unsigned long id)
{
@@ -413,6 +414,7 @@ void nvmap_unpin(struct nvmap_client *client, struct nvmap_handle_ref *ref)
if (handle_unpin(client, ref->handle, false))
wake_up(&client->share->pin_wait);
}
+EXPORT_SYMBOL(nvmap_unpin);
void nvmap_unpin_handles(struct nvmap_client *client,
struct nvmap_handle **h, int nr)
@@ -501,6 +503,7 @@ void *nvmap_mmap(struct nvmap_handle_ref *ref)
* nvmap_handle_put will be called by unmapping this address */
return p;
}
+EXPORT_SYMBOL(nvmap_mmap);
void nvmap_munmap(struct nvmap_handle_ref *ref, void *addr)
{
@@ -523,6 +526,7 @@ void nvmap_munmap(struct nvmap_handle_ref *ref, void *addr)
}
nvmap_handle_put(h);
}
+EXPORT_SYMBOL(nvmap_munmap);
struct nvmap_handle_ref *nvmap_alloc(struct nvmap_client *client, size_t size,
size_t align, unsigned int flags,
@@ -550,6 +554,7 @@ struct nvmap_handle_ref *nvmap_alloc(struct nvmap_client *client, size_t size,
return r;
}
+EXPORT_SYMBOL(nvmap_alloc);
/* allocates memory with specifed iovm_start address. */
struct nvmap_handle_ref *nvmap_alloc_iovm(struct nvmap_client *client,
@@ -605,6 +610,7 @@ void nvmap_free(struct nvmap_client *client, struct nvmap_handle_ref *r)
nvmap_free_handle_id(client, nvmap_ref_to_id(r));
}
+EXPORT_SYMBOL(nvmap_free);
int nvmap_mark_global(struct nvmap_client *client, struct nvmap_handle_ref *r)
{
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index 3b0db14f16ca..3ea7bd2ea797 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -87,6 +87,7 @@ struct nvmap_device {
};
struct nvmap_device *nvmap_dev;
+EXPORT_SYMBOL(nvmap_dev);
static struct backing_dev_info nvmap_bdi = {
.ra_pages = 0,
@@ -670,6 +671,7 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev,
spin_unlock(&dev->clients_lock);
return client;
}
+EXPORT_SYMBOL(nvmap_create_client);
static void destroy_client(struct nvmap_client *client)
{
@@ -756,6 +758,7 @@ void nvmap_client_put(struct nvmap_client *client)
if (!atomic_dec_return(&client->count))
destroy_client(client);
}
+EXPORT_SYMBOL(nvmap_client_put);
static int nvmap_open(struct inode *inode, struct file *filp)
{
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
index 4b7760b22190..c1add8383e83 100644
--- a/drivers/video/tegra/nvmap/nvmap_handle.c
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -572,9 +572,10 @@ static int handle_page_alloc(struct nvmap_client *client,
#ifdef CONFIG_NVMAP_PAGE_POOLS
struct nvmap_page_pool *pool = NULL;
struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
+ unsigned long paddr;
#endif
gfp_t gfp = GFP_NVMAP;
- unsigned long kaddr, paddr;
+ unsigned long kaddr;
pte_t **pte = NULL;
if (h->userflags & NVMAP_HANDLE_ZEROED_PAGES) {
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 9a94f7e093dd..8d41441b05ed 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -217,17 +217,20 @@ config TEGRA_WATCHDOG
depends on ARCH_TEGRA
help
Say Y here to include support for the watchdog timer
- embedded in NVIDIA Tegra SoCs.
+ embedded in NVIDIA Tegra SoCs. The default timeout
+ is set to 60 seconds.
To compile this driver as a module, choose M here: the
module will be called tegra_wdt.
-config TEGRA_WATCHDOG_ENABLE_ON_PROBE
- tristate "Turn on Tegra watchdog at system start up"
- depends on ARCH_TEGRA && TEGRA_WATCHDOG
+config TEGRA_WATCHDOG_ENABLE_HEARTBEAT
+ bool "Use the first Tegra watchdog as kernel heartbeats"
+ depends on TEGRA_WATCHDOG
+ default n
help
- Say Y here to enable the tegra watchdog at driver
- probe time, rather than when the device is opened.
+ Say Y here to enable the first tegra watchdog at driver
+ probe time. The kernel will reload the watchdog by
+ itself in an interrupt handler.
config EP93XX_WATCHDOG
tristate "EP93xx Watchdog"
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
index 1bcd726ebbd6..d32c516b2c55 100644
--- a/drivers/watchdog/tegra_wdt.c
+++ b/drivers/watchdog/tegra_wdt.c
@@ -4,6 +4,7 @@
* watchdog driver for NVIDIA tegra internal watchdog
*
* Copyright (c) 2012, NVIDIA Corporation.
+ * Copyright (c) 2013, Toradex AG
*
* based on drivers/watchdog/softdog.c and drivers/watchdog/omap_wdt.c
*
@@ -42,13 +43,33 @@
/* minimum and maximum watchdog trigger periods, in seconds */
#define MIN_WDT_PERIOD 5
#define MAX_WDT_PERIOD 1000
+
/* Assign Timer 7 to Timer 10 for WDT0 to WDT3, respectively */
#define TMR_SRC_START 7
+/*
+ * For spinlock lockup detection to work, the heartbeat should be 2*lockup
+ * for cases where the spinlock disabled irqs.
+ * Must be between MIN_WDT_PERIOD and MAX_WDT_PERIOD
+ */
+#define WDT_DEFAULT_TIME 60
+
+static int heartbeat = WDT_DEFAULT_TIME;
+static bool nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat period in seconds (default="
+ __MODULE_STRING(WDT_DEFAULT_TIME));
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+#endif
enum tegra_wdt_status {
WDT_DISABLED = 1 << 0,
WDT_ENABLED = 1 << 1,
- WDT_ENABLED_AT_PROBE = 1 << 2,
+ WDT_KERNEL_HEARTBEAT = 1 << 2,
};
struct tegra_wdt {
@@ -61,18 +82,15 @@ struct tegra_wdt {
void __iomem *wdt_source;
void __iomem *wdt_timer;
void __iomem *int_base;
- int irq;
int tmrsrc;
int timeout;
int status;
+ int way_out_ok;
+ struct tasklet_struct tasklet;
+ int irq;
+ int irq_counter;
};
-/*
- * For spinlock lockup detection to work, the heartbeat should be 2*lockup
- * for cases where the spinlock disabled irqs.
- */
-static int heartbeat = 120; /* must be greater than MIN_WDT_PERIOD and lower than MAX_WDT_PERIOD */
-
#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
#define TIMER_PTV 0x0
@@ -107,6 +125,16 @@ static void tegra_wdt_disable(struct tegra_wdt *wdt)
static inline void tegra_wdt_ping(struct tegra_wdt *wdt)
{
+ /* Reset timer */
+ tegra_wdt_enable(wdt);
+
+ /* Reenable IRQ in case an interrupt already happend */
+ if (wdt->irq_counter) {
+ writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR);
+ wdt->irq_counter = 0;
+ enable_irq(wdt->irq);
+ }
+
return;
}
@@ -114,9 +142,30 @@ static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id)
{
struct tegra_wdt *wdt = dev_id;
- writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR);
+ wdt->irq_counter++;
+
+ if (wdt->status & WDT_KERNEL_HEARTBEAT) {
+ tegra_wdt_ping(wdt);
+ } else {
+ /* If not in heartbeat mode, disable IRQs to avoid IRQ storm
+ * We don't acknowledge the interrupt here since the user
+ * did not reload the timer in time. Upon next interrupt
+ * the system will reset...
+ */
+ tasklet_schedule(&wdt->tasklet);
+ disable_irq_nosync(irq);
+ }
+
return IRQ_HANDLED;
}
+
+static void tegra_wdt_do_tasklet(unsigned long data)
+{
+ struct tegra_wdt *wdt = (struct tegra_wdt *)data;
+ dev_info(wdt->miscdev.parent, "Watchdog interrupt received, system "
+ "will reset soon if no ping arrives\n");
+}
+
#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
#define TIMER_PTV 0
@@ -132,6 +181,7 @@ static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id)
#define WDT_CFG_PMC2CAR_RST_EN (1 << 15)
#define WDT_STATUS (4)
#define WDT_INTR_STAT (1 << 1)
+ #define WDT_STATUS_EXPIR_COUNTER (3 << 12)
#define WDT_CMD (8)
#define WDT_CMD_START_COUNTER (1 << 0)
#define WDT_CMD_DISABLE_COUNTER (1 << 1)
@@ -169,19 +219,21 @@ static void tegra_wdt_enable(struct tegra_wdt *wdt)
val |= (TIMER_EN | TIMER_PERIODIC);
writel(val, wdt->wdt_timer + TIMER_PTV);
- /* Interrupt handler is not required for user space
- * WDT accesses, since the caller is responsible to ping the
- * WDT to reset the counter before expiration, through ioctls.
+ writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD);
+
+ /* Interrupt handler is not required for user space since
+ * a warning in a fourth of time don't make sense. Then
+ * the interrupt line is also shared, so it can't be disabled
+ * if one watchdog is about to expire... (interrupt storm)
* SYS_RST_EN doesnt work as there is no external reset
* from Tegra.
*/
- val = wdt->tmrsrc | WDT_CFG_PERIOD | /*WDT_CFG_INT_EN |*/
+ val = wdt->tmrsrc | WDT_CFG_PERIOD | /* WDT_CFG_INT_EN | */
/*WDT_CFG_SYS_RST_EN |*/ WDT_CFG_PMC2CAR_RST_EN;
#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
val |= WDT_CFG_FIQ_INT_EN;
#endif
writel(val, wdt->wdt_source + WDT_CFG);
- writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD);
}
static void tegra_wdt_disable(struct tegra_wdt *wdt)
@@ -192,17 +244,30 @@ static void tegra_wdt_disable(struct tegra_wdt *wdt)
writel(0, wdt->wdt_timer + TIMER_PTV);
}
+static void tegra_wdt_interrupt_instance(struct tegra_wdt *wdt)
+{
+ WARN_ON_ONCE(!(wdt->status & WDT_KERNEL_HEARTBEAT));
+
+ if (wdt->status & WDT_KERNEL_HEARTBEAT) {
+ tegra_wdt_ping(wdt);
+ }
+}
+
static irqreturn_t tegra_wdt_interrupt(int irq, void *dev_id)
{
+ struct tegra_wdt *wdt = NULL;
unsigned i, status;
for (i = 0; i < MAX_NR_CPU_WDT; i++) {
- if (tegra_wdt[i] == NULL)
+ wdt = tegra_wdt[i];
+ if (wdt == NULL)
continue;
- status = readl(tegra_wdt[i]->wdt_source + WDT_STATUS);
- if ((tegra_wdt[i]->status & WDT_ENABLED) &&
- (status & WDT_INTR_STAT))
- tegra_wdt_ping(tegra_wdt[i]);
+ status = readl(wdt->wdt_source + WDT_STATUS);
+ if ((wdt->status & WDT_ENABLED) &&
+ (status & WDT_INTR_STAT))
+ {
+ tegra_wdt_interrupt_instance(wdt);
+ }
}
return IRQ_HANDLED;
@@ -228,6 +293,9 @@ static int tegra_wdt_open(struct inode *inode, struct file *file)
if (test_and_set_bit(1, &wdt->users))
return -EBUSY;
+ /* Reset no way out, we need a new magic again */
+ wdt->way_out_ok = 0;
+
wdt->status |= WDT_ENABLED;
wdt->timeout = heartbeat;
tegra_wdt_enable(wdt);
@@ -239,13 +307,19 @@ static int tegra_wdt_release(struct inode *inode, struct file *file)
{
struct tegra_wdt *wdt = file->private_data;
- if (wdt->status == WDT_ENABLED) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- tegra_wdt_disable(wdt);
- wdt->status = WDT_DISABLED;
-#endif
+ if (wdt->status & WDT_ENABLED && !nowayout) {
+ if (wdt->way_out_ok) {
+ tegra_wdt_disable(wdt);
+ wdt->status = WDT_DISABLED;
+ } else {
+ dev_info(wdt->miscdev.parent, "No Magic Close "
+ "received, watchdog not disabled!\n");
+ }
+ } else if (nowayout) {
+ dev_info(wdt->miscdev.parent, "No way out is "
+ "enabled, watchdog not disabled!\n");
}
- wdt->users = 0;
+ clear_bit(1, &wdt->users);
return 0;
}
@@ -288,11 +362,10 @@ static long tegra_wdt_ioctl(struct file *file, unsigned int cmd,
return put_user(wdt->timeout, (int __user *)arg);
case WDIOC_SETOPTIONS:
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
if (get_user(option, (int __user *)arg))
return -EFAULT;
spin_lock(&lock);
- if (option & WDIOS_DISABLECARD) {
+ if (option & WDIOS_DISABLECARD && !nowayout) {
wdt->status &= ~WDT_ENABLED;
wdt->status |= WDT_DISABLED;
tegra_wdt_disable(wdt);
@@ -306,9 +379,6 @@ static long tegra_wdt_ioctl(struct file *file, unsigned int cmd,
}
spin_unlock(&lock);
return 0;
-#else
- return -EINVAL;
-#endif
}
return -ENOTTY;
}
@@ -316,6 +386,19 @@ static long tegra_wdt_ioctl(struct file *file, unsigned int cmd,
static ssize_t tegra_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
+ struct tegra_wdt *wdt = file->private_data;
+
+ /* check if way-out char was written as last data */
+ char c;
+ if(len) {
+ tegra_wdt_ping(wdt);
+
+ if(get_user(c, data + len - 1))
+ return -EFAULT;
+ else
+ wdt->way_out_ok = (('V' == c) ? 1 : 0);
+ }
+
return len;
}
@@ -333,8 +416,14 @@ static int tegra_wdt_probe(struct platform_device *pdev)
struct resource *res_src, *res_wdt, *res_irq;
struct resource *res_int_base = NULL;
struct tegra_wdt *wdt;
- u32 src;
int ret = 0;
+#ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_HEARTBEAT
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ int is_heartbeat_wdt = 1;
+#else
+ int is_heartbeat_wdt = !(pdev->id);
+#endif
+#endif
if (pdev->id < -1 && pdev->id > 3) {
dev_err(&pdev->dev, "only IDs 3:0 supported\n");
@@ -369,7 +458,6 @@ static int tegra_wdt_probe(struct platform_device *pdev)
return -ENOMEM;
}
- wdt->irq = -1;
wdt->miscdev.parent = &pdev->dev;
if (pdev->id == -1) {
wdt->miscdev.minor = WATCHDOG_MINOR;
@@ -410,12 +498,17 @@ static int tegra_wdt_probe(struct platform_device *pdev)
goto fail;
}
- src = readl(wdt->wdt_source);
- if (src & BIT(12))
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ /* Watchdog of Tegra 3 are not at the reset controller regs */
+ if (readl(wdt->wdt_source) & BIT(12))
dev_info(&pdev->dev, "last reset due to watchdog timeout\n");
+#endif
tegra_wdt_disable(wdt);
writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR);
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ writel(WDT_CMD_START_COUNTER, wdt->wdt_source + WDT_CMD);
+#endif
if (res_irq != NULL) {
#ifdef CONFIG_TEGRA_FIQ_DEBUGGER
@@ -436,6 +529,7 @@ static int tegra_wdt_probe(struct platform_device *pdev)
goto fail;
tegra_wdt_int_priority(wdt);
#endif
+ wdt->irq = -1;
ret = request_irq(res_irq->start, tegra_wdt_interrupt,
IRQF_DISABLED, dev_name(&pdev->dev), wdt);
if (ret) {
@@ -464,24 +558,26 @@ static int tegra_wdt_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, wdt);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ tasklet_init(&wdt->tasklet, tegra_wdt_do_tasklet, (unsigned long)wdt);
+#endif
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
-#ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_ON_PROBE
- /* Init and enable watchdog on WDT0 with timer 8 during probe */
- if (!(pdev->id)) {
- u32 val = 0;
- wdt->status = WDT_ENABLED | WDT_ENABLED_AT_PROBE;
+#ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_HEARTBEAT
+ /* Enable first watchdog during probe */
+ if (is_heartbeat_wdt) {
+ wdt->status = WDT_ENABLED | WDT_KERNEL_HEARTBEAT;
wdt->timeout = heartbeat;
+ set_bit(1, &wdt->users);
tegra_wdt_enable(wdt);
- val = readl(wdt->wdt_source + WDT_CFG);
- val |= WDT_CFG_INT_EN;
- writel(val, wdt->wdt_source + WDT_CFG);
- pr_info("WDT heartbeat enabled on probe\n");
+ pr_info("WDT kernel heartbeat enabled on probe\n");
}
#endif
+
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
tegra_wdt[pdev->id] = wdt;
#endif
- pr_info("%s done\n", __func__);
+
+ dev_info(&pdev->dev, "%s done\n", __func__);
return 0;
fail:
if (wdt->irq != -1)
@@ -543,16 +639,6 @@ static int tegra_wdt_resume(struct platform_device *pdev)
if (wdt->status & WDT_ENABLED)
tegra_wdt_enable(wdt);
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- /* Enable interrupt for WDT3 heartbeat watchdog */
- if (wdt->status & WDT_ENABLED_AT_PROBE) {
- u32 val = 0;
- val = readl(wdt->wdt_source + WDT_CFG);
- val |= WDT_CFG_INT_EN;
- writel(val, wdt->wdt_source + WDT_CFG);
- pr_info("WDT heartbeat enabled on probe\n");
- }
-#endif
return 0;
}
#endif
@@ -586,10 +672,6 @@ module_exit(tegra_wdt_exit);
MODULE_AUTHOR("NVIDIA Corporation");
MODULE_DESCRIPTION("Tegra Watchdog Driver");
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat,
- "Watchdog heartbeat period in seconds");
-
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("platform:tegra_wdt");
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index d494001b1226..fcdcb5d5c995 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -170,6 +170,16 @@ extern int __gpio_cansleep(unsigned gpio);
extern int __gpio_to_irq(unsigned gpio);
+#define GPIOF_DIR_OUT (0 << 0)
+#define GPIOF_DIR_IN (1 << 0)
+
+#define GPIOF_INIT_LOW (0 << 1)
+#define GPIOF_INIT_HIGH (1 << 1)
+
+#define GPIOF_IN (GPIOF_DIR_IN)
+#define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
+#define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
+
/**
* struct gpio - a structure describing a GPIO with configuration
* @gpio: the GPIO number
diff --git a/include/linux/colibri_usb.h b/include/linux/colibri_usb.h
new file mode 100644
index 000000000000..6b3949979c38
--- /dev/null
+++ b/include/linux/colibri_usb.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This 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 _COLIBRI_USB_H_
+#define _COLIBRI_USB_H_
+
+struct colibri_otg_platform_data {
+ int cable_detect_gpio;
+ struct platform_device* (*host_register)(void);
+ void (*host_unregister)(struct platform_device*);
+};
+
+#endif /* _COLIBRI_USB_H_ */
diff --git a/include/linux/input/fusion_F0710A.h b/include/linux/input/fusion_F0710A.h
new file mode 100644
index 000000000000..7d152cbdd06e
--- /dev/null
+++ b/include/linux/input/fusion_F0710A.h
@@ -0,0 +1,20 @@
+/* linux/input/fusion_F0710A.h
+ *
+ * Platform data for Fusion F0710A driver
+ *
+ * Copyright (c) 2013 Toradex AG (stefan.agner@toradex.ch)
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+
+#ifndef __LINUX_I2C_FUSION_F0710A_H
+#define __LINUX_I2C_FUSION_F0710A_H
+
+/* Board specific touch screen initial values */
+struct fusion_f0710a_init_data {
+ int (*pinmux_fusion_pins)(void);
+ int gpio_int;
+ int gpio_reset;
+};
+
+#endif /* __LINUX_I2C_FUSION_F0710A_H */
diff --git a/include/linux/linux_logo.h b/include/linux/linux_logo.h
index ca5bd91d12e1..2be299513819 100644
--- a/include/linux/linux_logo.h
+++ b/include/linux/linux_logo.h
@@ -47,6 +47,7 @@ extern const struct linux_logo logo_superh_vga16;
extern const struct linux_logo logo_superh_clut224;
extern const struct linux_logo logo_m32r_clut224;
extern const struct linux_logo logo_spe_clut224;
+extern const struct linux_logo logo_custom_clut224;
extern const struct linux_logo *fb_find_logo(int depth);
#ifdef CONFIG_FB_LOGO_EXTRA
diff --git a/include/linux/lm95245.h b/include/linux/lm95245.h
new file mode 100644
index 000000000000..ecc7ec57696a
--- /dev/null
+++ b/include/linux/lm95245.h
@@ -0,0 +1,37 @@
+/*
+ * include/linux/lm95245.h
+ *
+ * LM95245, temperature monitoring device from National Semiconductors
+ *
+ * Copyright (c) 2013, Toradex, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This 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 _LINUX_LM95245_H
+#define _LINUX_LM95245_H
+
+struct lm95245_platform_data {
+ bool enable_os_pin;
+ void (*probe_callback)(struct device *dev);
+};
+
+void lm95245_get_local_temp(struct device *dev, int *temp);
+void lm95245_get_remote_temp(struct device *dev, int *temp);
+void lm95245_set_remote_os_limit(struct device *dev, int temp);
+void lm95245_set_remote_critical_limit(struct device *dev, int temp);
+void lm95245_set_local_shared_os__critical_limit(struct device *dev, int val);
+
+#endif /* _LINUX_LM95245_H */
diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h
index be1af7c42e57..b584ea64a16a 100644
--- a/include/linux/mfd/stmpe.h
+++ b/include/linux/mfd/stmpe.h
@@ -10,6 +10,17 @@
#include <linux/device.h>
+#define SAMPLE_TIME(x) ((x & 0xf) << 4)
+#define MOD_12B(x) ((x & 0x1) << 3)
+#define REF_SEL(x) ((x & 0x1) << 1)
+#define ADC_FREQ(x) (x & 0x3)
+#define AVE_CTRL(x) ((x & 0x3) << 6)
+#define DET_DELAY(x) ((x & 0x7) << 3)
+#define SETTLING(x) (x & 0x7)
+#define FRACTION_Z(x) (x & 0x7)
+#define I_DRIVE(x) (x & 0x1)
+#define OP_MODE(x) ((x & 0x7) << 1)
+
enum stmpe_block {
STMPE_BLOCK_GPIO = 1 << 0,
STMPE_BLOCK_KEYPAD = 1 << 1,
@@ -174,6 +185,26 @@ struct stmpe_ts_platform_data {
};
/**
+ * struct stmpe_adc_platform_data - stmpe811 adc controller platform
+ * data
+ * @sample_time: ADC converstion time in number of clock.
+ * (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks,
+ * 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks),
+ * recommended is 4.
+ * @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC)
+ * @ref_sel: ADC reference source
+ * (0 -> internal reference, 1 -> external reference)
+ * @adc_freq: ADC Clock speed
+ * (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz)
+ */
+struct stmpe_adc_platform_data {
+ u8 sample_time;
+ u8 mod_12b;
+ u8 ref_sel;
+ u8 adc_freq;
+};
+
+/**
* struct stmpe_platform_data - STMPE platform data
* @id: device id to distinguish between multiple STMPEs on the same board
* @blocks: bitmask of blocks to enable (use STMPE_BLOCK_*)
@@ -199,6 +230,7 @@ struct stmpe_platform_data {
struct stmpe_gpio_platform_data *gpio;
struct stmpe_keypad_platform_data *keypad;
struct stmpe_ts_platform_data *ts;
+ struct stmpe_adc_platform_data *adc;
};
#define STMPE_NR_INTERNAL_IRQS 9
diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h
index 702cee59cc7b..b5e990e9f6ee 100644
--- a/include/linux/mfd/tps6586x.h
+++ b/include/linux/mfd/tps6586x.h
@@ -56,7 +56,6 @@ enum pwm_pfm_mode {
PWM_ONLY,
AUTO_PWM_PFM,
PWM_DEFAULT_VALUE,
-
};
enum slew_rate_settings {
@@ -71,6 +70,14 @@ enum slew_rate_settings {
SLEW_RATE_DEFAULT_VALUE,
};
+enum tps6586x_type {
+ TPS658621A = 0x15,
+ TPS658621D = 0x2c,
+ TPS658623 = 0x1b,
+ TPS658643 = 0x03,
+ TPS6586X_ANY = -1,
+};
+
struct tps6586x_settings {
/* SM0, SM1 and SM2 have PWM-only and auto PWM/PFM mode */
enum pwm_pfm_mode sm_pwm_mode;
@@ -128,5 +135,6 @@ extern int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask);
extern int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask);
extern int tps6586x_update(struct device *dev, int reg, uint8_t val,
uint8_t mask);
+extern enum tps6586x_type tps6586x_gettype(struct device *dev);
#endif /*__LINUX_MFD_TPS6586X_H */
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 5ee48390decc..db86304e1c28 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -93,6 +93,8 @@ struct sdhci_host {
#define SDHCI_QUIRK_NON_STANDARD_TUNING (1ULL<<33)
/* Controller doesn't calculate max_discard_to */
#define SDHCI_QUIRK_NO_CALC_MAX_DISCARD_TO (1ULL<<34)
+/* The system physically doesn't support 1.8v, even if the host does */
+#define SDHCI_QUIRK2_NO_1_8_V (1ULL<<35)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h
index 59f928aaa07f..9ad666f987ea 100644
--- a/include/linux/platform_data/tegra_usb.h
+++ b/include/linux/platform_data/tegra_usb.h
@@ -98,6 +98,7 @@ struct tegra_usb_dev_mode_data {
*/
struct tegra_usb_host_mode_data {
int vbus_gpio;
+ int vbus_gpio_inverted;
const char *vbus_reg;
bool hot_plug;
bool remote_wakeup_supported;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index cc09c562e479..b4793408969d 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -495,14 +495,12 @@ static struct global_cwq *get_gcwq(unsigned int cpu)
static atomic_t *get_pool_nr_running(struct worker_pool *pool)
{
int cpu = pool->gcwq->cpu;
- atomic_t (*nr_running)[NR_WORKER_POOLS];
+ int idx = worker_pool_pri(pool);
if (cpu != WORK_CPU_UNBOUND)
- nr_running = &per_cpu(pool_nr_running, cpu);
+ return &per_cpu(pool_nr_running, cpu)[idx];
else
- nr_running = &unbound_pool_nr_running;
-
- return nr_running[worker_pool_pri(pool)];
+ return &unbound_pool_nr_running[idx];
}
static struct cpu_workqueue_struct *get_cwq(unsigned int cpu,
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 862dd35260d0..e46cc984f9de 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -480,7 +480,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a)
else
buf2[0] = '\0';
- printk(KERN_INFO "HDMI: supports coding type %s:"
+ printk(KERN_DEBUG "HDMI: supports coding type %s:"
" channels = %d, rates =%s%s\n",
cea_audio_coding_type_names[a->format],
a->channels,
@@ -504,14 +504,14 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
{
int i;
- printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n",
+ printk(KERN_DEBUG "HDMI: detected monitor %s at connection type %s\n",
e->monitor_name,
eld_connection_type_names[e->conn_type]);
if (e->spk_alloc) {
char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
- printk(KERN_INFO "HDMI: available speakers:%s\n", buf);
+ printk(KERN_DEBUG "HDMI: available speakers:%s\n", buf);
}
for (i = 0; i < e->sad_count; i++)
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 5942395099ad..ac509cd68f6f 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -702,7 +702,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
int pin_idx;
struct hdmi_eld *eld;
- printk(KERN_INFO
+ printk(KERN_DEBUG
"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
codec->addr, pin_nid, pd, eldv);
@@ -952,7 +952,7 @@ static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid,
if (eld->monitor_present)
eld_valid = !!(present & AC_PINSENSE_ELDV);
- printk(KERN_INFO
+ printk(KERN_DEBUG
"HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
codec->addr, pin_nid, eld->monitor_present, eld_valid);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index cb4d30305059..80a520b1ff4b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1188,7 +1188,10 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
}
ass = codec->subsystem_id & 0xffff;
+#ifndef CONFIG_MACH_APALIS_T30
+/* Hack: avoid crash due to codec->bus->pci being NULL */
if (ass != codec->bus->pci->subsystem_device && (ass & 1))
+#endif
goto do_sku;
nid = 0x1d;
@@ -1268,7 +1271,10 @@ static int alc_subsystem_id(struct hda_codec *codec,
}
ass = codec->subsystem_id & 0xffff;
+#ifndef CONFIG_MACH_APALIS_T30
+/* Hack: avoid crash due to codec->bus->pci being NULL */
if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
+#endif
goto do_sku;
/* invalid SSID, check the special NID pin defcfg instead */
@@ -1503,7 +1509,12 @@ static void alc_pick_fixup(struct hda_codec *codec,
}
}
if (id < 0) {
+#ifdef CONFIG_MACH_APALIS_T30
+/* Hack: avoid crash due to codec->bus->pci being NULL */
+ quirk = NULL;
+#else
quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+#endif
if (quirk) {
id = quirk->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 7e4066e131e6..86d46ef9947c 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -20,6 +20,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/pcm.h>
@@ -130,27 +131,24 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
/* change mic bias resistor to 4Kohm */
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
- SGTL5000_BIAS_R_4k, SGTL5000_BIAS_R_4k);
+ SGTL5000_BIAS_R_MASK,
+ SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT);
break;
case SND_SOC_DAPM_PRE_PMD:
- /*
- * SGTL5000_BIAS_R_8k as mask to clean the two bits
- * of mic bias and output impedance
- */
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
- SGTL5000_BIAS_R_8k, 0);
+ SGTL5000_BIAS_R_MASK, 0);
break;
}
return 0;
}
/*
- * using codec assist to small pop, hp_powerup or lineout_powerup
- * should stay setting until vag_powerup is fully ramped down,
- * vag fully ramped down require 400ms.
+ * As manual described, ADC/DAC only works when VAG powerup,
+ * So enabled VAG before ADC/DAC up.
+ * In power down case, we need wait 400ms when vag fully ramped down.
*/
-static int small_pop_event(struct snd_soc_dapm_widget *w,
+static int power_vag_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
switch (event) {
@@ -159,7 +157,7 @@ static int small_pop_event(struct snd_soc_dapm_widget *w,
SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
break;
- case SND_SOC_DAPM_PRE_PMD:
+ case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
SGTL5000_VAG_POWERUP, 0);
msleep(400);
@@ -204,12 +202,8 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
mic_bias_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0,
- small_pop_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_PGA_E("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0,
- small_pop_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux),
SND_SOC_DAPM_MUX("Headphone Mux", SND_SOC_NOPM, 0, 0, &dac_mux),
@@ -224,8 +218,11 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
0, SGTL5000_CHIP_DIG_POWER,
1, 0),
- SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0),
+ SND_SOC_DAPM_SUPPLY("VAG_POWER", SGTL5000_CHIP_ANA_POWER, 7, 0,
+ power_vag_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0),
SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0),
};
@@ -234,13 +231,16 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Capture Mux", "LINE_IN", "LINE_IN"}, /* line_in --> adc_mux */
{"Capture Mux", "MIC_IN", "MIC_IN"}, /* mic_in --> adc_mux */
+ {"ADC", NULL, "VAG_POWER"},
{"ADC", NULL, "Capture Mux"}, /* adc_mux --> adc */
{"AIFOUT", NULL, "ADC"}, /* adc --> i2s_out */
+ {"DAC", NULL, "VAG_POWER"},
{"DAC", NULL, "AIFIN"}, /* i2s-->dac,skip audio mux */
{"Headphone Mux", "DAC", "DAC"}, /* dac --> hp_mux */
{"LO", NULL, "DAC"}, /* dac --> line_out */
+ {"LINE_IN", NULL, "VAG_POWER"},
{"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */
{"HP", NULL, "Headphone Mux"}, /* hp_mux --> hp */
@@ -367,7 +367,7 @@ static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0);
/* tlv for mic gain, 0db 20db 30db 40db */
static const unsigned int mic_gain_tlv[] = {
- TLV_DB_RANGE_HEAD(4),
+ TLV_DB_RANGE_HEAD(2),
0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0),
};
@@ -402,7 +402,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
5, 1, 0),
SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL,
- 0, 4, 0, mic_gain_tlv),
+ 0, 3, 0, mic_gain_tlv),
};
/* mute the codec used by alsa core */
@@ -725,7 +725,9 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL, i2s_ctl, i2s_ctl);
+ snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL,
+ SGTL5000_I2S_DLEN_MASK | SGTL5000_I2S_SCLKFREQ_MASK,
+ i2s_ctl);
return 0;
}
@@ -756,7 +758,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev)
/* set voltage to register */
snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
- (0x1 << 4) - 1, reg);
+ SGTL5000_LINREG_VDDD_MASK, reg);
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
SGTL5000_LINEREG_D_POWERUP,
@@ -782,7 +784,7 @@ static int ldo_regulator_disable(struct regulator_dev *dev)
/* clear voltage info */
snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
- (0x1 << 4) - 1, 0);
+ SGTL5000_LINREG_VDDD_MASK, 0);
ldo->enabled = 0;
@@ -808,6 +810,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec,
int voltage)
{
struct ldo_regulator *ldo;
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
ldo = kzalloc(sizeof(struct ldo_regulator), GFP_KERNEL);
@@ -842,6 +845,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec,
return ret;
}
+ sgtl5000->ldo = ldo;
return 0;
}
@@ -986,12 +990,12 @@ static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
/* restore regular registers */
for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += 2) {
- /* this regs depends on the others */
+ /* These regs should restore in particular order */
if (reg == SGTL5000_CHIP_ANA_POWER ||
reg == SGTL5000_CHIP_CLK_CTRL ||
reg == SGTL5000_CHIP_LINREG_CTRL ||
reg == SGTL5000_CHIP_LINE_OUT_CTRL ||
- reg == SGTL5000_CHIP_CLK_CTRL)
+ reg == SGTL5000_CHIP_REF_CTRL)
continue;
snd_soc_write(codec, reg, cache[reg]);
@@ -1002,8 +1006,17 @@ static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
snd_soc_write(codec, reg, cache[reg]);
/*
- * restore power and other regs according
- * to set_power() and set_clock()
+ * restore these regs according to the power setting sequence in
+ * sgtl5000_set_power_regs() and clock setting sequence in
+ * sgtl5000_set_clock().
+ *
+ * The order of restore is:
+ * 1. SGTL5000_CHIP_CLK_CTRL MCLK_FREQ bits (1:0) should be restore after
+ * SGTL5000_CHIP_ANA_POWER PLL bits set
+ * 2. SGTL5000_CHIP_LINREG_CTRL should be set before
+ * SGTL5000_CHIP_ANA_POWER LINREG_D restored
+ * 3. SGTL5000_CHIP_REF_CTRL controls Analog Ground Voltage,
+ * prefer to resotre it after SGTL5000_CHIP_ANA_POWER restored
*/
snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL,
cache[SGTL5000_CHIP_LINREG_CTRL]);
@@ -1115,7 +1128,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
/* set voltage to register */
snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
- (0x1 << 4) - 1, 0x8);
+ SGTL5000_LINREG_VDDD_MASK, 0x8);
/*
* if vddd linear reg has been enabled,
@@ -1146,8 +1159,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP;
snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
- vag << SGTL5000_ANA_GND_SHIFT,
- vag << SGTL5000_ANA_GND_SHIFT);
+ SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT);
/* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
vag = vddio / 2;
@@ -1161,9 +1173,8 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
SGTL5000_LINE_OUT_GND_STP;
snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
- vag << SGTL5000_LINE_OUT_GND_SHIFT |
- SGTL5000_LINE_OUT_CURRENT_360u <<
- SGTL5000_LINE_OUT_CURRENT_SHIFT,
+ SGTL5000_LINE_OUT_CURRENT_MASK |
+ SGTL5000_LINE_OUT_GND_MASK,
vag << SGTL5000_LINE_OUT_GND_SHIFT |
SGTL5000_LINE_OUT_CURRENT_360u <<
SGTL5000_LINE_OUT_CURRENT_SHIFT);
@@ -1331,7 +1342,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
SGTL5000_HP_ZCD_EN |
SGTL5000_ADC_ZCD_EN);
- snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 0);
+ snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2);
/*
* disable DAP
@@ -1436,10 +1447,17 @@ static const struct i2c_device_id sgtl5000_id[] = {
MODULE_DEVICE_TABLE(i2c, sgtl5000_id);
+static const struct of_device_id sgtl5000_dt_ids[] = {
+ { .compatible = "fsl,sgtl5000", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids);
+
static struct i2c_driver sgtl5000_i2c_driver = {
.driver = {
.name = "sgtl5000",
.owner = THIS_MODULE,
+ .of_match_table = sgtl5000_dt_ids,
},
.probe = sgtl5000_i2c_probe,
.remove = __devexit_p(sgtl5000_i2c_remove),
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h
index eec3ab368f39..8a9f43534b79 100644
--- a/sound/soc/codecs/sgtl5000.h
+++ b/sound/soc/codecs/sgtl5000.h
@@ -280,7 +280,7 @@
/*
* SGTL5000_CHIP_MIC_CTRL
*/
-#define SGTL5000_BIAS_R_MASK 0x0200
+#define SGTL5000_BIAS_R_MASK 0x0300
#define SGTL5000_BIAS_R_SHIFT 8
#define SGTL5000_BIAS_R_WIDTH 2
#define SGTL5000_BIAS_R_off 0x0
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index de8309be3816..a47a746a2b7e 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -4,6 +4,17 @@ config SND_SOC_TEGRA
help
Say Y or M here if you want support for SoC audio on Tegra.
+config SND_SOC_TEGRA20_AC97
+ tristate "Tegra 20 AC97 driver"
+ select AC97_BUS
+ select SND_AC97_CODEC
+ select SND_SOC_AC97_BUS
+ select SND_SOC_TEGRA20_DAS
+ help
+ Say Y or M if you want to add support for codecs attached to the
+ Tegra AC97 interface. You will also need to select the individual
+ machine drivers to support below.
+
config SND_SOC_TEGRA20_DAS
tristate "Tegra 20 Digital Audio Switch driver"
depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
@@ -76,6 +87,29 @@ config SND_SOC_TEGRA_WM8903
boards using the WM8093 codec. Currently, the supported boards are
Harmony, Ventana, Seaboard, Kaen, and Aebl.
+config SND_SOC_TEGRA_COLIBRI_T20
+ tristate "SoC Audio support for Colibri T20 module"
+ depends on SND_SOC_TEGRA && MACH_COLIBRI_T20
+ select SND_SOC_SPDIF
+ select SND_SOC_TEGRA20_AC97
+ select SND_SOC_TEGRA20_SPDIF
+ select SND_SOC_WM9712
+ help
+ Say Y or M here if you want to add support for SoC audio on the
+ Toradex Colibri T20 module.
+
+config SND_SOC_TEGRA_COLIBRI_T30
+ tristate "SoC Audio support for Apalis/Colibri T30 modules"
+ depends on I2C && (MACH_APALIS_T30 || MACH_COLIBRI_T30) && SND_SOC_TEGRA
+ select SND_SOC_SGTL5000
+ select SND_SOC_SPDIF
+ select SND_SOC_TEGRA30_DAM
+ select SND_SOC_TEGRA30_I2S
+ select SND_SOC_TEGRA30_SPDIF
+ help
+ Say Y or M here if you want to add support for SoC audio on the
+ Toradex Apalis/Colibri T30 modules.
+
config SND_SOC_TEGRA_TRIMSLICE
tristate "SoC Audio support for TrimSlice board"
depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 83f30054a085..594c963cb8ea 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -8,6 +8,7 @@ snd-soc-tegra-tdm-pcm-objs := tegra_tdm_pcm.o
snd-soc-tegra20-spdif-objs := tegra20_spdif.o
snd-soc-tegra-utils-objs += tegra_asoc_utils.o
snd-soc-tegra20-das-objs := tegra20_das.o
+snd-soc-tegra20-ac97-objs := tegra20_ac97.o
snd-soc-tegra20-i2s-objs := tegra20_i2s.o
snd-soc-tegra30-ahub-objs := tegra30_ahub.o
snd-soc-tegra30-i2s-objs := tegra30_i2s.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-tdm-pcm.o
obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o
+obj-$(CONFIG_SND_SOC_TEGRA20_AC97) += snd-soc-tegra20-ac97.o
obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
obj-$(CONFIG_SND_SOC_TEGRA30_DAM) += snd-soc-tegra30-dam.o
@@ -27,6 +29,8 @@ obj-$(CONFIG_SND_SOC_TEGRA30_SPDIF) += snd-soc-tegra30-spdif.o
# Tegra machine Support
snd-soc-tegra-wm8903-objs := tegra_wm8903.o
+snd-soc-tegra-colibri_t20-objs := colibri_t20.o
+snd-soc-tegra-colibri_t30-objs := colibri_t30.o
snd-soc-tegra-trimslice-objs := trimslice.o
snd-soc-tegra-wm8753-objs := tegra_wm8753.o
snd-soc-tegra-max98088-objs := tegra_max98088.o
@@ -36,6 +40,8 @@ snd-soc-tegra-max98095-objs := tegra_max98095.o
snd-soc-tegra-vcm-objs := tegra_vcm.o
obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
+obj-$(CONFIG_SND_SOC_TEGRA_COLIBRI_T20) += snd-soc-tegra-colibri_t20.o
+obj-$(CONFIG_SND_SOC_TEGRA_COLIBRI_T30) += snd-soc-tegra-colibri_t30.o
obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
obj-$(CONFIG_SND_SOC_TEGRA_MAX98088) += snd-soc-tegra-max98088.o
diff --git a/sound/soc/tegra/colibri_t20.c b/sound/soc/tegra/colibri_t20.c
new file mode 100644
index 000000000000..744328b7b9ec
--- /dev/null
+++ b/sound/soc/tegra/colibri_t20.c
@@ -0,0 +1,393 @@
+/*
+ * SoC audio driver for Toradex Colibri T20
+ *
+ * Copyright (C) 2012 Toradex Inc.
+ *
+ * 2010-11-19: Marcel Ziswiler <marcel.ziswiler@noser.com>
+ * initial version (note: WM9715L is fully WM9712 compatible)
+ *
+ * Copied from tosa.c:
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ * Richard Purdie <richard@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <asm/mach-types.h>
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+
+#include <mach/audio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h> /* order crucial */
+#include <sound/soc-dapm.h>
+
+#include "../codecs/wm9712.h"
+#include "tegra_asoc_utils.h"
+#include "tegra_pcm.h"
+#include "tegra20_ac97.h"
+
+#define DRV_NAME "colibri_t20-snd-wm9715l"
+
+struct colibri_t20_wm9715l {
+ struct tegra_asoc_utils_data util_data;
+};
+
+static int colibri_t20_wm9715l_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = codec->card;
+ struct colibri_t20_wm9715l *machine = snd_soc_card_get_drvdata(card);
+ int srate, mclk;
+ int err;
+
+ srate = params_rate(params);
+
+ /* AC97 clock is really fixed */
+ mclk = 24576000;
+
+ err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+ if (err < 0) {
+ if (!(machine->util_data.set_mclk % mclk))
+ mclk = machine->util_data.set_mclk;
+ else {
+ dev_err(card->dev, "Can't configure clocks\n");
+ return err;
+ }
+ }
+
+ tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
+
+//DAS AC97 DAC to DAP switching already done at probe
+
+ return 0;
+}
+
+static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct colibri_t20_wm9715l *machine = snd_soc_card_get_drvdata(card);
+ int srate, mclk, min_mclk;
+ int err;
+
+ srate = params_rate(params);
+ switch (srate) {
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ mclk = 11289600;
+ break;
+ case 8000:
+ case 16000:
+ case 32000:
+ case 48000:
+ case 64000:
+ case 96000:
+ mclk = 12288000;
+ break;
+ default:
+ return -EINVAL;
+ }
+ min_mclk = 128 * srate;
+
+ err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+ if (err < 0) {
+ if (!(machine->util_data.set_mclk % min_mclk))
+ mclk = machine->util_data.set_mclk;
+ else {
+ dev_err(card->dev, "Can't configure clocks\n");
+ return err;
+ }
+ }
+
+ tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
+
+ return 0;
+}
+
+static int tegra_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct colibri_t20_wm9715l *machine = snd_soc_card_get_drvdata(rtd->card);
+
+ tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0);
+
+ return 0;
+}
+
+static struct snd_soc_ops colibri_t20_wm9715l_ops = {
+ .hw_params = colibri_t20_wm9715l_hw_params,
+ .hw_free = tegra_hw_free,
+};
+
+static struct snd_soc_ops tegra_spdif_ops = {
+ .hw_params = tegra_spdif_hw_params,
+ .hw_free = tegra_hw_free,
+};
+
+static const struct snd_soc_dapm_widget colibri_t20_wm9715l_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("HEADPHONE", NULL),
+ SND_SOC_DAPM_LINE("LINEIN", NULL),
+ SND_SOC_DAPM_MIC("MIC_IN", NULL),
+};
+
+/* Currently supported audio map */
+static const struct snd_soc_dapm_route colibri_t20_wm9715l_audio_map[] = {
+ /* Colibri SODIMM pin 1 (MIC_IN)
+ Colibri Evaluation Board: Audio jack X26 bottom pink
+ Iris: Audio header X9 pin 2
+ Orchid: Audio jack X11 bottom pink MIC in */
+ { "MIC_IN", NULL, "MIC1" },
+
+ /* Colibri SODIMM pin 5 & 7 (LINEIN_L/R)
+ Colibri Evaluation Board: Audio jack X26 top blue
+ Iris: Audio header X9 pin 4 & 3
+ MECS Tellurium: Audio jack X11 pin 1 & 2
+ Orchid: Audio jack X11 top blue line in */
+ { "LINEIN", NULL, "LINEINL" },
+ { "LINEIN", NULL, "LINEINR" },
+
+ /* Colibri SODIMM pin 15 & 17 (HEADPHONE_L/R)
+ Colibri Evaluation Board: Audio jack X26 middle green
+ Iris: Audio jack X8
+ MECS Tellurium: Audio jack X11 pin 4 & 5 (HEADPHONE_LF/RF)
+ Orchid: Audio jack X11 middle green line out
+ Protea: Audio jack X53 line out */
+ { "HEADPHONE", NULL, "LOUT2" },
+ { "HEADPHONE", NULL, "ROUT2" },
+};
+
+static int colibri_t20_wm9715l_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ pr_info("%s()\n", __func__);
+
+//GPIOs
+
+ /* add Colibri T20 specific widgets */
+ err = snd_soc_dapm_new_controls(dapm, colibri_t20_wm9715l_dapm_widgets,
+ ARRAY_SIZE(colibri_t20_wm9715l_dapm_widgets));
+ if (err)
+ return err;
+
+ /* set up Colibri T20 specific audio path audio_map */
+ err = snd_soc_dapm_add_routes(dapm, colibri_t20_wm9715l_audio_map, ARRAY_SIZE(colibri_t20_wm9715l_audio_map));
+ if (err)
+ return err;
+
+//jack detection
+
+ /* connected pins */
+ snd_soc_dapm_enable_pin(dapm, "HPOUTL");
+ snd_soc_dapm_enable_pin(dapm, "HPOUTR");
+ snd_soc_dapm_enable_pin(dapm, "LINEINL");
+ snd_soc_dapm_enable_pin(dapm, "LINEINR");
+ snd_soc_dapm_enable_pin(dapm, "MIC1");
+
+ /* Activate Mic Bias */
+ snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
+
+ /* not connected pins */
+ snd_soc_dapm_nc_pin(dapm, "LOUT2");
+ snd_soc_dapm_nc_pin(dapm, "MIC2");
+ snd_soc_dapm_nc_pin(dapm, "MONOOUT");
+ snd_soc_dapm_nc_pin(dapm, "OUT3");
+ snd_soc_dapm_nc_pin(dapm, "PCBEEP");
+ snd_soc_dapm_nc_pin(dapm, "PHONE");
+ snd_soc_dapm_nc_pin(dapm, "ROUT2");
+
+ err = snd_soc_dapm_sync(dapm);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static struct snd_soc_dai_link colibri_t20_wm9715l_dai[] = {
+ {
+ .name = "AC97",
+// .name = "AC97 HiFi",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai_name = "tegra20-ac97-pcm",
+ .codec_dai_name = "wm9712-hifi",
+ .platform_name = "tegra-pcm-audio",
+ .codec_name = "wm9712-codec",
+ .init = colibri_t20_wm9715l_init,
+ .ops = &colibri_t20_wm9715l_ops,
+ },
+//order
+ {
+ .name = "SPDIF",
+ .stream_name = "SPDIF PCM",
+ .codec_name = "spdif-dit.0",
+ .platform_name = "tegra-pcm-audio",
+ .cpu_dai_name = "tegra20-spdif",
+ .codec_dai_name = "dit-hifi",
+ .ops = &tegra_spdif_ops,
+ },
+#if 0
+ {
+ .name = "AC97 Aux",
+ .stream_name = "AC97 Aux",
+ .cpu_dai_name = "tegra20-ac97-modem",
+ .codec_dai_name = "wm9712-aux",
+ .platform_name = "tegra-pcm-audio",
+ .codec_name = "wm9712-codec",
+ },
+#endif
+};
+
+//power management
+
+static struct snd_soc_card snd_soc_colibri_t20_wm9715l = {
+ .name = "colibri_t20-wm9715l",
+ .dai_link = colibri_t20_wm9715l_dai,
+ .num_links = ARRAY_SIZE(colibri_t20_wm9715l_dai),
+// .suspend_post = colibri_t20_wm9715l_suspend_post,
+// .resume_pre = colibri_t20_wm9715l_resume_pre,
+};
+
+//
+static struct platform_device *colibri_t20_snd_wm9715l_device;
+
+static __devinit int colibri_t20_wm9715l_driver_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_colibri_t20_wm9715l;
+ struct colibri_t20_wm9715l *machine;
+ int ret;
+
+ pr_info("%s()\n", __func__);
+
+ if (!machine_is_colibri_t20())
+ return -ENODEV;
+
+//make sure tegra20-ac97 is properly loaded to avoid subsequent crash
+
+ machine = kzalloc(sizeof(struct colibri_t20_wm9715l), GFP_KERNEL);
+ if (!machine) {
+ dev_err(&pdev->dev, "Can't allocate colibri_t20_wm9715l struct\n");
+ return -ENOMEM;
+ }
+
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
+ if (ret)
+ goto err_free_machine;
+
+//regulator handling
+
+//switch handling
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, machine);
+
+ /* explicitly instanciate AC97 codec */
+ colibri_t20_snd_wm9715l_device = platform_device_alloc("wm9712-codec", -1);
+ if (!colibri_t20_snd_wm9715l_device) {
+ dev_err(&pdev->dev, "platform_device_alloc of wm9712-codec failed (%d)\n",
+ ret);
+ goto err_fini_utils;
+ }
+
+ ret = platform_device_add(colibri_t20_snd_wm9715l_device);
+ if (ret) {
+ dev_err(&pdev->dev, "platform_device_add of wm9712-codec failed (%d)\n",
+ ret);
+ goto err_device_put;
+ }
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err_device_del;
+ }
+
+ if (!card->instantiated) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err_unregister_card;
+ }
+
+ return 0;
+
+err_unregister_card:
+ snd_soc_unregister_card(card);
+err_device_del:
+ platform_device_del(colibri_t20_snd_wm9715l_device);
+err_device_put:
+ platform_device_put(colibri_t20_snd_wm9715l_device);
+err_fini_utils:
+ tegra_asoc_utils_fini(&machine->util_data);
+err_free_machine:
+ kfree(machine);
+ return ret;
+}
+
+static int __devexit colibri_t20_wm9715l_driver_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct colibri_t20_wm9715l *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+ platform_device_unregister(colibri_t20_snd_wm9715l_device);
+
+ tegra_asoc_utils_fini(&machine->util_data);
+
+ kfree(machine);
+
+ return 0;
+}
+
+static struct platform_driver colibri_t20_wm9715l_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+// .pm = &snd_soc_pm_ops,
+ },
+ .probe = colibri_t20_wm9715l_driver_probe,
+ .remove = __devexit_p(colibri_t20_wm9715l_driver_remove),
+};
+
+static int __init colibri_t20_wm9715l_modinit(void)
+{
+ return platform_driver_register(&colibri_t20_wm9715l_driver);
+}
+
+static void __exit colibri_t20_wm9715l_modexit(void)
+{
+ platform_driver_unregister(&colibri_t20_wm9715l_driver);
+}
+
+module_init(colibri_t20_wm9715l_modinit);
+module_exit(colibri_t20_wm9715l_modexit);
+
+/* Module information */
+MODULE_AUTHOR("Marcel Ziswiler <marcel.ziswiler@toradex.com>");
+MODULE_DESCRIPTION("ALSA SoC WM9715L on Toradex Colibri T20");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/colibri_t30.c b/sound/soc/tegra/colibri_t30.c
new file mode 100644
index 000000000000..6390be5b8d6b
--- /dev/null
+++ b/sound/soc/tegra/colibri_t30.c
@@ -0,0 +1,412 @@
+/*
+ * SoC audio driver for Toradex Colibri T30
+ *
+ * Copyright (C) 2012 Toradex Inc.
+ *
+ * 2012-02-12: Marcel Ziswiler <marcel.ziswiler@toradex.com>
+ * initial version
+ *
+ * Copied from tegra_wm8903.c
+ * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <asm/mach-types.h>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <mach/tegra_asoc_pdata.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/sgtl5000.h"
+
+#include "tegra_pcm.h"
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-colibri_t30-sgtl5000"
+
+struct colibri_t30_sgtl5000 {
+ struct tegra_asoc_utils_data util_data;
+ struct tegra_asoc_platform_data *pdata;
+ enum snd_soc_bias_level bias_level;
+};
+
+static int colibri_t30_sgtl5000_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = codec->card;
+ struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
+ int srate, mclk, i2s_daifmt;
+ int err;
+ int rate;
+
+ /* sgtl5000 does not support 512*rate when in 96000 fs */
+ srate = params_rate(params);
+ switch (srate) {
+ case 96000:
+ mclk = 256 * srate;
+ break;
+ default:
+ mclk = 512 * srate;
+ break;
+ }
+
+ /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */
+ if (mclk < 8000000 || mclk > 27000000)
+ return -EINVAL;
+
+ if(pdata->i2s_param[HIFI_CODEC].is_i2s_master) {
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS;
+ } else {
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+ }
+
+ err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+ if (err < 0) {
+ if (!(machine->util_data.set_mclk % mclk))
+ mclk = machine->util_data.set_mclk;
+ else {
+ dev_err(card->dev, "Can't configure clocks\n");
+ return err;
+ }
+ }
+
+ tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
+
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
+
+ /* Use DSP mode for mono on Tegra20 */
+ if (params_channels(params) != 2) {
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ } else {
+ switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev,
+ "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+ }
+
+ err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai fmt not set\n");
+ return err;
+ }
+
+ err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt);
+ if (err < 0) {
+ dev_err(card->dev, "cpu_dai fmt not set\n");
+ return err;
+ }
+
+ /* Set SGTL5000's SYSCLK (provided by clk_out_1) */
+ err = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, rate, SND_SOC_CLOCK_IN);
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai clock not set\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(card);
+ int srate, mclk, min_mclk;
+ int err;
+
+ srate = params_rate(params);
+ switch (srate) {
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ mclk = 11289600;
+ break;
+ case 8000:
+ case 16000:
+ case 32000:
+ case 48000:
+ case 64000:
+ case 96000:
+ mclk = 12288000;
+ break;
+ default:
+ return -EINVAL;
+ }
+ min_mclk = 128 * srate;
+
+ err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+ if (err < 0) {
+ if (!(machine->util_data.set_mclk % min_mclk))
+ mclk = machine->util_data.set_mclk;
+ else {
+ dev_err(card->dev, "Can't configure clocks\n");
+ return err;
+ }
+ }
+
+ tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
+
+ return 0;
+}
+
+static int tegra_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(rtd->card);
+
+ tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0);
+
+ return 0;
+}
+
+static struct snd_soc_ops colibri_t30_sgtl5000_ops = {
+ .hw_params = colibri_t30_sgtl5000_hw_params,
+ .hw_free = tegra_hw_free,
+};
+
+static struct snd_soc_ops tegra_spdif_ops = {
+ .hw_params = tegra_spdif_hw_params,
+ .hw_free = tegra_hw_free,
+};
+
+/* Colibri T30 machine DAPM widgets */
+static const struct snd_soc_dapm_widget colibri_t30_sgtl5000_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("HEADPHONE", NULL),
+ SND_SOC_DAPM_LINE("LINEIN", NULL),
+ SND_SOC_DAPM_MIC("MIC_IN", NULL),
+};
+
+/* Colibri T30 machine audio map (connections to the codec pins) */
+static const struct snd_soc_dapm_route colibri_t30_sgtl5000_dapm_route[] = {
+ /* Colibri SODIMM pin 1 (MIC_IN)
+ Colibri Evaluation Board: Audio jack X26 bottom pink
+ Iris: Audio header X9 pin 2
+ Orchid: Audio jack X11 bottom pink MIC in */
+//mic bias GPIO handling
+// [ 9.359733] tegra-snd-colibri_t30-sgtl5000 tegra-snd-colibri_t30-sgtl5000.0: Failed to add route MICIN->MIC_IN
+// { "MIC_IN", NULL, "MIC_IN" },
+
+ /* Colibri SODIMM pin 5 & 7 (LINEIN_L/R)
+ Colibri Evaluation Board: Audio jack X26 top blue
+ Iris: Audio header X9 pin 4 & 3
+ MECS Tellurium: Audio jack X11 pin 1 & 2
+ Orchid: Audio jack X11 top blue line in */
+ { "LINEIN", NULL, "LINE_IN" },
+
+ /* Colibri SODIMM pin 15 & 17 (HEADPHONE_L/R)
+ Colibri Evaluation Board: Audio jack X26 middle green
+ Iris: Audio jack X8
+ MECS Tellurium: Audio jack X11 pin 4 & 5 (HEADPHONE_LF/RF)
+ Orchid: Audio jack X11 middle green line out
+ Protea: Audio jack X53 line out */
+//HP PGA handling
+ { "HEADPHONE", NULL, "HP_OUT" },
+};
+
+static int colibri_t30_sgtl5000_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_card *card = codec->card;
+ struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ machine->bias_level = SND_SOC_BIAS_STANDBY;
+
+ ret = tegra_asoc_utils_register_ctls(&machine->util_data);
+ if (ret < 0)
+ return ret;
+
+ snd_soc_dapm_nc_pin(dapm, "LINE_OUT");
+
+ snd_soc_dapm_sync(dapm);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link colibri_t30_sgtl5000_dai[] = {
+ {
+ .name = "SGTL5000",
+ .stream_name = "SGTL5000 PCM",
+ .codec_name = "sgtl5000.4-000a",
+ .platform_name = "tegra-pcm-audio",
+ .cpu_dai_name = "tegra30-i2s.2",
+ .codec_dai_name = "sgtl5000",
+ .init = colibri_t30_sgtl5000_init,
+ .ops = &colibri_t30_sgtl5000_ops,
+ },
+ {
+ .name = "SPDIF",
+ .stream_name = "SPDIF PCM",
+ .codec_name = "spdif-dit.0",
+ .platform_name = "tegra-pcm-audio",
+ .cpu_dai_name = "tegra30-spdif",
+ .codec_dai_name = "dit-hifi",
+ .ops = &tegra_spdif_ops,
+ },
+};
+
+static struct snd_soc_card snd_soc_colibri_t30_sgtl5000 = {
+ .name = "colibri_t30-sgtl5000",
+ .dai_link = colibri_t30_sgtl5000_dai,
+ .num_links = ARRAY_SIZE(colibri_t30_sgtl5000_dai),
+// .set_bias_level
+// .set_bias_level_post
+};
+
+static __devinit int colibri_t30_sgtl5000_driver_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_colibri_t30_sgtl5000;
+ struct colibri_t30_sgtl5000 *machine;
+ struct tegra_asoc_platform_data *pdata;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data supplied\n");
+ return -EINVAL;
+ }
+
+ machine = kzalloc(sizeof(struct colibri_t30_sgtl5000), GFP_KERNEL);
+ if (!machine) {
+ dev_err(&pdev->dev, "Can't allocate colibri_t30_sgtl5000 struct\n");
+ return -ENOMEM;
+ }
+
+ machine->pdata = pdata;
+
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
+ if (ret)
+ goto err_free_machine;
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, machine);
+
+ card->dapm_widgets = colibri_t30_sgtl5000_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(colibri_t30_sgtl5000_dapm_widgets);
+
+ card->dapm_routes = colibri_t30_sgtl5000_dapm_route;
+ card->num_dapm_routes = ARRAY_SIZE(colibri_t30_sgtl5000_dapm_route);
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err_fini_utils;
+ }
+
+ if (!card->instantiated) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err_unregister_card;
+ }
+
+ ret = tegra_asoc_utils_set_parent(&machine->util_data,
+ pdata->i2s_param[HIFI_CODEC].is_i2s_master);
+ if (ret) {
+ dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n",
+ ret);
+ goto err_unregister_card;
+ }
+
+ return 0;
+
+err_unregister_card:
+ snd_soc_unregister_card(card);
+err_fini_utils:
+ tegra_asoc_utils_fini(&machine->util_data);
+err_free_machine:
+ kfree(machine);
+ return ret;
+}
+
+static int __devexit colibri_t30_sgtl5000_driver_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct colibri_t30_sgtl5000 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+ tegra_asoc_utils_fini(&machine->util_data);
+
+ kfree(machine);
+
+ return 0;
+}
+
+static struct platform_driver colibri_t30_sgtl5000_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = colibri_t30_sgtl5000_driver_probe,
+ .remove = __devexit_p(colibri_t30_sgtl5000_driver_remove),
+};
+
+static int __init colibri_t30_sgtl5000_modinit(void)
+{
+ return platform_driver_register(&colibri_t30_sgtl5000_driver);
+}
+module_init(colibri_t30_sgtl5000_modinit);
+
+static void __exit colibri_t30_sgtl5000_modexit(void)
+{
+ platform_driver_unregister(&colibri_t30_sgtl5000_driver);
+}
+module_exit(colibri_t30_sgtl5000_modexit);
+
+/* Module information */
+MODULE_AUTHOR("Marcel Ziswiler <marcel.ziswiler@toradex.com>");
+MODULE_DESCRIPTION("ALSA SoC SGTL5000 on Toradex Colibri T30");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
new file mode 100644
index 000000000000..9b7ddb667860
--- /dev/null
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -0,0 +1,651 @@
+/*
+ * sound/soc/tegra/tegra20_ac97.c
+ *
+ * Copyright (C) 2012 Toradex, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <mach/ac97.h>
+#include <mach/audio.h>
+#include <mach/dma.h>
+#include <mach/gpio.h>
+#include <mach/iomap.h>
+
+#include <sound/ac97_codec.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "../../../arch/arm/mach-tegra/gpio-names.h"
+#include "tegra_pcm.h"
+#include "tegra20_ac97.h"
+#include "tegra20_das.h"
+
+#define DRV_NAME "tegra20-ac97"
+
+//required?
+static DEFINE_MUTEX(car_mutex);
+
+#define check_ifc(n, ...) if ((n) > TEGRA_DAI_AC97_MODEM) { \
+ pr_err("%s: invalid AC97 interface %d\n", __func__, (n)); \
+ return __VA_ARGS__; \
+}
+
+/* required due to AC97 codec drivers not adhering to proper platform driver
+ model */
+static struct tegra20_ac97 *ac97;
+
+static int tegra20_ac97_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+pr_info("%s %u fmt=%d", __func__, __LINE__, fmt);
+ return 0;
+}
+
+phys_addr_t ac97_get_fifo_phy_base(struct tegra20_ac97 *ac97, int ifc, int fifo)
+{
+ check_ifc(ifc, 0);
+
+ if (ifc == TEGRA_DAI_AC97_PCM)
+ return (phys_addr_t)ac97->phys + (fifo ? AC_AC_FIFO_IN1_0 : AC_AC_FIFO_OUT1_0);
+ else
+ return (phys_addr_t)ac97->phys + (fifo ? AC_AC_FIFO_IN2_0 : AC_AC_FIFO_OUT2_0);
+}
+
+static int tegra20_ac97_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai);
+
+ pr_info("%s(): dai->id=%d, %s\n", __func__, dai->id, (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)?"play":"rec");
+
+//TODO: adaptable sample size
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ac97->playback_dma_data.addr =
+ ac97_get_fifo_phy_base(ac97, dai->id, AC97_FIFO_TX);
+ ac97->playback_dma_data.wrap = 4;
+ ac97->playback_dma_data.width = 32;
+ } else {
+ ac97->capture_dma_data.addr =
+ ac97_get_fifo_phy_base(ac97, dai->id, AC97_FIFO_RX);
+ ac97->capture_dma_data.wrap = 4;
+ ac97->capture_dma_data.width = 32;
+ }
+
+ return 0;
+}
+
+int ac97_fifo_set_attention_level(struct tegra20_ac97 *ac97, int ifc, int fifo, unsigned level)
+{
+ u32 val;
+
+ pr_info("%s()\n", __func__);
+
+ check_ifc(ifc, -EINVAL);
+
+ if (ifc == TEGRA_DAI_AC97_PCM)
+ val = readl(ac97->regs + AC_AC_FIFO1_SCR_0);
+ else
+ val = readl(ac97->regs + AC_AC_FIFO2_SCR_0);
+
+ if (fifo) {
+ val &= ~(AC_AC_FIFOx_SCR_REC_FIFOx_FULL_EN |
+ AC_AC_FIFOx_SCR_REC_FIFOx_3QRT_FULL_EN |
+ AC_AC_FIFOx_SCR_REC_FIFOx_QRT_FULL_EN |
+ AC_AC_FIFOx_SCR_REC_FIFOx_NOT_MT_EN);
+ switch (level) {
+ case AC97_FIFO_ATN_LVL_NONE:
+ break;
+ case AC97_FIFO_ATN_LVL_FULL:
+ val |= AC_AC_FIFOx_SCR_REC_FIFOx_FULL_EN;
+ break;
+ case AC97_FIFO_ATN_LVL_3QUART:
+ val |= AC_AC_FIFOx_SCR_REC_FIFOx_3QRT_FULL_EN;
+ break;
+ case AC97_FIFO_ATN_LVL_QUART:
+ val |= AC_AC_FIFOx_SCR_REC_FIFOx_QRT_FULL_EN;
+ break;
+ case AC97_FIFO_ATN_LVL_EMPTY:
+ val |= AC_AC_FIFOx_SCR_REC_FIFOx_NOT_MT_EN;
+ break;
+ default:
+ pr_err("%s: invalid FIFO level selector %d\n", __func__,
+ level);
+ return -EINVAL;
+ }
+ }
+ else {
+ val &= ~(AC_AC_FIFOx_SCR_PB_FIFOx_NOT_FULL_EN |
+ AC_AC_FIFOx_SCR_PB_FIFOx_QRT_MT_EN |
+ AC_AC_FIFOx_SCR_PB_FIFOx_3QRT_MT_EN |
+ AC_AC_FIFOx_SCR_PB_FIFOx_MT_EN);
+ switch (level) {
+ case AC97_FIFO_ATN_LVL_NONE:
+ break;
+ case AC97_FIFO_ATN_LVL_FULL:
+ val |= AC_AC_FIFOx_SCR_PB_FIFOx_NOT_FULL_EN;
+ break;
+ case AC97_FIFO_ATN_LVL_3QUART:
+ val |= AC_AC_FIFOx_SCR_PB_FIFOx_3QRT_MT_EN;
+ break;
+ case AC97_FIFO_ATN_LVL_QUART:
+ val |= AC_AC_FIFOx_SCR_PB_FIFOx_QRT_MT_EN;
+ break;
+ case AC97_FIFO_ATN_LVL_EMPTY:
+ val |= AC_AC_FIFOx_SCR_PB_FIFOx_MT_EN;
+ break;
+ default:
+ pr_err("%s: invalid FIFO level selector %d\n", __func__,
+ level);
+ return -EINVAL;
+ }
+ }
+
+ if (ifc == TEGRA_DAI_AC97_PCM)
+ writel(val, ac97->regs + AC_AC_FIFO1_SCR_0);
+ else
+ writel(val, ac97->regs + AC_AC_FIFO2_SCR_0);
+
+ return 0;
+}
+
+void ac97_slot_enable(struct tegra20_ac97 *ac97, int ifc, int fifo, int on)
+{
+ pr_info("%s()\n", __func__);
+
+ check_ifc(ifc);
+
+ if (!fifo) {
+ u32 val;
+
+ val = readl(ac97->regs + AC_AC_CTRL_0);
+
+ if (ifc == TEGRA_DAI_AC97_PCM)
+ if (on) {
+#ifndef TEGRA_AC97_32BIT_PLAYBACK
+ /* Enable packed mode for now */
+ val |= AC_AC_CTRL_STM_EN;
+#endif
+ val |= AC_AC_CTRL_PCM_DAC_EN;
+ } else
+ val &= ~AC_AC_CTRL_PCM_DAC_EN;
+ else
+ if (on) {
+#ifndef TEGRA_AC97_32BIT_PLAYBACK
+ /* Enable packed mode for now */
+ val |= AC_AC_CTRL_STM2_EN;
+#endif
+ val |= AC_AC_CTRL_LINE1_DAC_EN;
+ } else
+ val &= ~AC_AC_CTRL_LINE1_DAC_EN;
+
+ writel(val, ac97->regs + AC_AC_CTRL_0);
+ }
+}
+
+/* playback */
+static inline void tegra20_ac97_start_playback(struct snd_soc_dai *cpu_dai)
+{
+ struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(cpu_dai);
+
+ pr_info("%s()\n", __func__);
+
+ ac97_fifo_set_attention_level(ac97, cpu_dai->id, AC97_FIFO_TX,
+ /* Only FIFO level proven stable for video playback */
+#ifdef TEGRA_AC97_32BIT_PLAYBACK
+ AC97_FIFO_ATN_LVL_QUART);
+#else
+ AC97_FIFO_ATN_LVL_EMPTY);
+#endif
+ ac97_slot_enable(ac97, cpu_dai->id, AC97_FIFO_TX, 1);
+}
+
+static inline void tegra20_ac97_stop_playback(struct snd_soc_dai *cpu_dai)
+{
+ struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(cpu_dai);
+ int delay_cnt = 10; /* 1ms max wait for fifo to drain */
+
+ pr_info("%s()\n", __func__);
+
+ ac97_fifo_set_attention_level(ac97, cpu_dai->id, AC97_FIFO_TX,
+ AC97_FIFO_ATN_LVL_NONE);
+
+//something wrong?
+ while (!(readl(ac97->regs + AC_AC_CTRL_0) &
+ AC_AC_FIFOx_SCR_PB_FIFOx_UNDERRUN_INT_STA) &&
+ delay_cnt)
+ {
+ udelay(100);
+ delay_cnt--;
+ }
+
+ ac97_slot_enable(ac97, cpu_dai->id, AC97_FIFO_TX, 0);
+}
+
+/* recording */
+static inline void tegra20_ac97_start_capture(struct snd_soc_dai *cpu_dai)
+{
+ struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(cpu_dai);
+//check slot validity in received tag information
+ ac97_fifo_set_attention_level(ac97, cpu_dai->id, AC97_FIFO_RX,
+ AC97_FIFO_ATN_LVL_FULL);
+}
+
+static inline void tegra20_ac97_stop_capture(struct snd_soc_dai *cpu_dai)
+{
+ struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(cpu_dai);
+ ac97_fifo_set_attention_level(ac97, cpu_dai->id, AC97_FIFO_RX,
+ AC97_FIFO_ATN_LVL_NONE);
+
+//wait?
+}
+
+static int tegra20_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ pr_info("%s()\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra20_ac97_start_playback(dai);
+ else
+ tegra20_ac97_start_capture(dai);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra20_ac97_stop_playback(dai);
+ else
+ tegra20_ac97_stop_capture(dai);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void tegra20_ac97_reset(struct snd_ac97 *ac97)
+{
+ int gpio_status;
+
+ pr_info("%s()\n", __func__);
+
+ /* do wolfson hard reset */
+#define GPIO_AC97_nRESET TEGRA_GPIO_PV0
+ gpio_status = gpio_request(GPIO_AC97_nRESET, "WOLFSON_RESET");
+ if (gpio_status < 0) {
+ pr_info("WOLFSON_RESET request GPIO FAILED\n");
+ WARN_ON(1);
+ }
+ gpio_status = gpio_direction_output(GPIO_AC97_nRESET, 0);
+ if (gpio_status < 0) {
+ pr_info("WOLFSON_RESET request GPIO DIRECTION FAILED\n");
+ WARN_ON(1);
+ }
+ udelay(2);
+ gpio_set_value(GPIO_AC97_nRESET, 1);
+ udelay(2);
+}
+
+static void tegra20_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ int gpio_status;
+
+ pr_info("%s()\n", __func__);
+
+ /* do wolfson warm reset by toggling SYNC */
+#define GPIO_AC97_SYNC TEGRA_GPIO_PP0
+ gpio_status = gpio_request(GPIO_AC97_SYNC, "WOLFSON_SYNC");
+ if (gpio_status < 0) {
+ pr_info("WOLFSON_SYNC request GPIO FAILED\n");
+ WARN_ON(1);
+ }
+ gpio_status = gpio_direction_output(GPIO_AC97_SYNC, 1);
+ if (gpio_status < 0) {
+ pr_info("WOLFSON_SYNC request GPIO DIRECTION FAILED\n");
+ WARN_ON(1);
+ }
+ udelay(2);
+ gpio_set_value(GPIO_AC97_SYNC, 0);
+ udelay(2);
+ gpio_free(GPIO_AC97_SYNC);
+}
+
+static unsigned short tegra20_ac97_read(struct snd_ac97 *ac97_snd, unsigned short reg)
+{
+// struct tegra20_ac97 *ac97 = ac97_snd->private_data;
+ u32 val;
+ int timeout = 100;
+
+//pr_info("%s(0x%04x)", __func__, reg);
+
+// mutex_lock(&car_mutex);
+
+ /* Set MSB=1 to indicate Read Command! */
+ writel((((reg | 0x80) << AC_AC_CMD_CMD_ADDR_SHIFT) &
+ AC_AC_CMD_CMD_ADDR_MASK) |
+ /* Set Busy Bit to start Command!! */
+ AC_AC_CMD_BUSY, ac97->regs + AC_AC_CMD_0);
+
+ while (!((val = readl(ac97->regs + AC_AC_STATUS1_0)) &
+ AC_AC_STATUS1_STA_VALID1) && timeout--)
+ mdelay(1);
+
+// mutex_unlock(&car_mutex);
+
+//pr_info(" = 0x%04x\n", (val & AC_AC_STATUS1_STA_DATA1_MASK) >> AC_AC_STATUS1_STA_DATA1_SHIFT);
+
+ return (val & AC_AC_STATUS1_STA_DATA1_MASK) >>
+ AC_AC_STATUS1_STA_DATA1_SHIFT;
+}
+
+static void tegra20_ac97_write(struct snd_ac97 *ac97_snd, unsigned short reg,
+ unsigned short val)
+{
+// struct tegra20_ac97 *ac97 = ac97_snd->private_data;
+ int timeout = 100;
+
+//pr_info("%s(0x%04x, 0x%04x)\n", __func__, reg, val);
+
+// mutex_lock(&car_mutex);
+
+ writel(((reg << AC_AC_CMD_CMD_ADDR_SHIFT) & AC_AC_CMD_CMD_ADDR_MASK) |
+ ((val << AC_AC_CMD_CMD_DATA_SHIFT) &
+ AC_AC_CMD_CMD_DATA_MASK) |
+ /* Set Busy Bit to start Command!! */
+ AC_AC_CMD_BUSY, ac97->regs + AC_AC_CMD_0);
+
+ while (((val = readl(ac97->regs + AC_AC_CMD_0)) &
+ AC_AC_CMD_BUSY) && timeout--)
+ mdelay(1);
+
+// mutex_unlock(&car_mutex);
+}
+
+/* required by sound/soc/codecs/wm9712.c */
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = tegra20_ac97_read,
+ .reset = tegra20_ac97_reset,
+ .warm_reset = tegra20_ac97_warm_reset,
+ .write = tegra20_ac97_write,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static struct snd_ac97_bus_ops tegra20_ac97_ops = {
+ .read = tegra20_ac97_read,
+ /* reset already done above */
+ .write = tegra20_ac97_write,
+};
+
+static int tegra20_ac97_probe(struct snd_soc_dai *dai)
+{
+//hw_probe: reset GPIO, clk_get, clk_enable, request_irq
+ struct tegra20_ac97 *ac97 = snd_soc_dai_get_drvdata(dai);
+
+ pr_info("%s()\n", __func__);
+ pr_info("ac97->capture_dma_data=%p\n", &ac97->capture_dma_data);
+ pr_info("ac97->playback_dma_data=%p\n", &ac97->playback_dma_data);
+
+ dai->capture_dma_data = &ac97->capture_dma_data;
+ dai->playback_dma_data = &ac97->playback_dma_data;
+
+ return 0;
+}
+
+//TODO: power management
+
+static struct snd_soc_dai_ops tegra20_ac97_dai_ops = {
+ .hw_params = tegra20_ac97_hw_params,
+//
+ .set_fmt = tegra20_ac97_set_fmt,
+//
+ .trigger = tegra20_ac97_trigger,
+};
+
+struct snd_soc_dai_driver tegra20_ac97_dai[] = {
+ {
+ .name = DRV_NAME "-pcm",
+// .id = 0,
+ .probe = tegra20_ac97_probe,
+//.resume
+ .playback = {
+// .stream_name = "AC97 PCM Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AC97_SAMPLE_RATES,
+#ifndef TEGRA_AC97_32BIT_PLAYBACK
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+#else
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+#endif
+ },
+ .capture = {
+// .stream_name = "AC97 PCM Recording",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AC97_SAMPLE_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &tegra20_ac97_dai_ops,
+ .symmetric_rates = 1,
+ },
+#if 0
+ {
+ .name = DRV_NAME "-modem",
+// .id = 1,
+ .playback = {
+ .stream_name = "AC97 Modem Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = AC97_SAMPLE_RATES,
+#ifndef TEGRA_AC97_32BIT_PLAYBACK
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+#else
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+#endif
+ },
+ .capture = {
+ .stream_name = "AC97 Modem Recording",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = AC97_SAMPLE_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &tegra20_ac97_dai_ops,
+ .symmetric_rates = 1,
+ },
+#endif
+};
+
+static __devinit int tegra20_ac97_platform_probe(struct platform_device *pdev)
+{
+ struct resource *mem, *memregion, *dmareq;
+ int ret;
+ struct snd_ac97_bus *ac97_bus;
+
+ pr_info("%s()\n", __func__);
+
+ ac97 = kzalloc(sizeof(struct tegra20_ac97), GFP_KERNEL);
+ if (!ac97) {
+ dev_err(&pdev->dev, "Can't allocate tegra20_ac97\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ dev_set_drvdata(&pdev->dev, ac97);
+
+ ac97->clk_ac97 = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ac97->clk_ac97)) {
+ dev_err(&pdev->dev, "Can't retrieve AC97 clock\n");
+ ret = PTR_ERR(ac97->clk_ac97);
+ goto err_free;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ ret = -ENODEV;
+ goto err_clk_put;
+ }
+ ac97->phys = mem->start;
+
+ dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmareq) {
+ dev_err(&pdev->dev, "No DMA resource\n");
+ ret = -ENODEV;
+ goto err_clk_put;
+ }
+
+ memregion = request_mem_region(mem->start, resource_size(mem),
+ DRV_NAME);
+ if (!memregion) {
+ dev_err(&pdev->dev, "Memory region already claimed\n");
+ ret = -EBUSY;
+ goto err_clk_put;
+ }
+
+ ac97->regs = ioremap(mem->start, resource_size(mem));
+ if (!ac97->regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ ac97->capture_dma_data.req_sel = dmareq->start;
+ ac97->playback_dma_data.req_sel = dmareq->start;
+
+ ret = snd_soc_register_dais(&pdev->dev, tegra20_ac97_dai, ARRAY_SIZE(tegra20_ac97_dai));
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register DAIs\n");
+ goto err_unmap;
+ }
+
+//required?
+#if 1
+//use 1 in order for actual card to get 0 which is used as default e.g. in Android
+// ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ ret = snd_card_create(1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &ac97->card);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed creating snd_card!\n");
+ goto err_create;
+ }
+
+ ac97->card->dev = &pdev->dev;
+ strncpy(ac97->card->driver, pdev->dev.driver->name, sizeof(ac97->card->driver));
+#endif
+
+pr_info("%s() %u\n", __func__, __LINE__);
+ /* put propper DAC to DAP DAS path in place */
+
+ ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC3,
+ TEGRA20_DAS_DAP_ID_3);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set dap-dac path\n");
+ goto err_create;
+ }
+
+ ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_3,
+ TEGRA20_DAS_DAP_SEL_DAC3);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set dac-dap path\n");
+ goto err_create;
+ }
+
+pr_info("%s() %u\n", __func__, __LINE__);
+ ret = snd_ac97_bus(ac97->card, 0, &tegra20_ac97_ops, NULL, &ac97_bus);
+ if (ret) {
+ dev_err(&pdev->dev, "failed registerign ac97_bus!\n");
+ goto err_create;
+ }
+
+ return 0;
+
+err_create:
+ snd_card_free(ac97->card);
+err_unmap:
+ iounmap(ac97->regs);
+err_release:
+ release_mem_region(mem->start, resource_size(mem));
+err_clk_put:
+ clk_put(ac97->clk_ac97);
+err_free:
+ kfree(ac97);
+exit:
+pr_info("%s() %u\n", __func__, __LINE__);
+ return ret;
+}
+
+static int __devexit tegra20_ac97_platform_remove(struct platform_device *pdev)
+{
+ struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev);
+ struct resource *res;
+
+ snd_card_free(ac97->card);
+
+ snd_soc_unregister_dai(&pdev->dev);
+
+ iounmap(ac97->regs);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ clk_put(ac97->clk_ac97);
+
+ kfree(ac97);
+
+ return 0;
+}
+
+static struct platform_driver tegra20_ac97_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra20_ac97_platform_probe,
+ .remove = __devexit_p(tegra20_ac97_platform_remove),
+};
+
+static int __init snd_tegra20_ac97_init(void)
+{
+ return platform_driver_register(&tegra20_ac97_driver);
+}
+module_init(snd_tegra20_ac97_init);
+
+static void __exit snd_tegra20_ac97_exit(void)
+{
+ platform_driver_unregister(&tegra20_ac97_driver);
+}
+module_exit(snd_tegra20_ac97_exit);
+
+MODULE_AUTHOR("Marcel Ziswiler <marcel.ziswiler@toradex.com>");
+MODULE_DESCRIPTION("Tegra AC97 ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra20_ac97.h b/sound/soc/tegra/tegra20_ac97.h
new file mode 100644
index 000000000000..430ecc1500f4
--- /dev/null
+++ b/sound/soc/tegra/tegra20_ac97.h
@@ -0,0 +1,43 @@
+/*
+ * linux/sound/soc/tegra/tegra20_ac97.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _TEGRA_AC97_H
+#define _TEGRA_AC97_H
+
+#include "tegra_pcm.h"
+
+/* Tegra DAI ID's */
+#define TEGRA_DAI_AC97_PCM 0 /* slot 3: PCM left channel */
+ /* slot 4: PCM right channel */
+#define TEGRA_DAI_AC97_MODEM 1 /* slot 5: modem line 1 */
+
+ /* slot 11: touch panel digitizer data */
+
+#define AC97_FIFO_ATN_LVL_NONE 0
+#define AC97_FIFO_ATN_LVL_EMPTY 1
+#define AC97_FIFO_ATN_LVL_QUART 2
+#define AC97_FIFO_ATN_LVL_3QUART 3
+#define AC97_FIFO_ATN_LVL_FULL 4
+
+#define AC97_FIFO_TX 0
+#define AC97_FIFO_RX 1
+
+#define AC97_SAMPLE_RATES SNDRV_PCM_RATE_8000_48000
+
+/* AC97 controller */
+struct tegra20_ac97 {
+ struct clk *dap_mclk;
+ struct clk *clk_ac97;
+ struct snd_card *card;
+ struct tegra_pcm_dma_params capture_dma_data;
+ phys_addr_t phys;
+ struct tegra_pcm_dma_params playback_dma_data;
+ void __iomem *regs;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index a7c9c0a110f9..8bd0af7df610 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -42,6 +42,12 @@
#define DRV_NAME "tegra-pcm-audio"
+#ifdef CONFIG_SND_SOC_TEGRA20_AC97
+/* AC97 capture conversion buffer pointers and sizes */
+static uint *conv_buf[MAX_DMA_REQ_COUNT];
+static uint conv_size[MAX_DMA_REQ_COUNT];
+#endif /* CONFIG_SND_SOC_TEGRA20_AC97 */
+
static const struct snd_pcm_hardware tegra_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -67,22 +73,28 @@ static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd)
unsigned long addr;
dma_req = &prtd->dma_req[prtd->dma_req_idx];
- if (++prtd->dma_req_idx >= prtd->dma_req_count)
- prtd->dma_req_idx -= prtd->dma_req_count;
if (prtd->avp_dma_addr)
addr = prtd->avp_dma_addr + prtd->dma_pos;
else
addr = buf->addr + prtd->dma_pos;
- prtd->dma_pos += dma_req->size;
- if (prtd->dma_pos >= prtd->dma_pos_end)
- prtd->dma_pos = 0;
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_req->source_addr = addr;
- else
+ else {
+#ifdef CONFIG_SND_SOC_TEGRA20_AC97
+ conv_buf[prtd->dma_req_idx] = (uint *)(buf->area + prtd->dma_pos);
+ conv_size[prtd->dma_req_idx] = dma_req->size;
+#endif /* CONFIG_SND_SOC_TEGRA20_AC97 */
dma_req->dest_addr = addr;
+ }
+
+ /* Do index and DMA position update last */
+ if (++prtd->dma_req_idx >= prtd->dma_req_count)
+ prtd->dma_req_idx -= prtd->dma_req_count;
+ prtd->dma_pos += dma_req->size;
+ if (prtd->dma_pos >= prtd->dma_pos_end)
+ prtd->dma_pos = 0;
tegra_dma_enqueue_req(prtd->dma_chan, dma_req);
}
@@ -100,6 +112,17 @@ static void dma_complete_callback(struct tegra_dma_req *req)
return;
}
+#ifdef CONFIG_SND_SOC_TEGRA20_AC97
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ while (conv_size[prtd->dma_req_idx]) {
+ /* Convert 20-bit AC97 sample to 32-bit */
+ *conv_buf[prtd->dma_req_idx] <<= 12;
+ conv_buf[prtd->dma_req_idx]++;
+ conv_size[prtd->dma_req_idx]-=4;
+ }
+ }
+#endif /* CONFIG_SND_SOC_TEGRA20_AC97 */
+
if (++prtd->period_index >= runtime->periods)
prtd->period_index = 0;