summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuriyan Ramasami <suriyan.r@gmail.com>2013-10-09 21:26:58 +0400
committerMauro Ribeiro <git@mdrjr.net>2013-10-09 21:26:58 +0400
commit286a81158f01dcb08e16d77790c21fd2a40afc6c (patch)
tree094bfcaeff9e84eb2c2c290d5b69651ddc7e0159
parent43d1d1444d9c3cec0dceec4d223bebc3c6093674 (diff)
downloadu-boot-286a81158f01dcb08e16d77790c21fd2a40afc6c.tar.xz
Configure USB3503 with i2c for CFG1 - self powered
-rw-r--r--arch/arm/cpu/armv7/exynos/Makefile1
-rw-r--r--arch/arm/cpu/armv7/exynos/usb3503_hkdk4212.c313
-rw-r--r--arch/arm/include/asm/arch-exynos/usb3503_hkdk4212.h83
-rw-r--r--drivers/usb/host/ehci-exynos.c26
4 files changed, 423 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv7/exynos/Makefile b/arch/arm/cpu/armv7/exynos/Makefile
index 5b5f952cf7..7dcae1e45d 100644
--- a/arch/arm/cpu/armv7/exynos/Makefile
+++ b/arch/arm/cpu/armv7/exynos/Makefile
@@ -41,6 +41,7 @@ COBJS += onenand_cp.o
ifdef CONFIG_HKDK4212
COBJS += pmic_hkdk4212.o
+COBJS += usb3503_hkdk4212.o
else
ifndef CONFIG_CPU_EXYNOS4X12
ifndef CONFIG_CPU_EXYNOS5250
diff --git a/arch/arm/cpu/armv7/exynos/usb3503_hkdk4212.c b/arch/arm/cpu/armv7/exynos/usb3503_hkdk4212.c
new file mode 100644
index 0000000000..7efb3b85f1
--- /dev/null
+++ b/arch/arm/cpu/armv7/exynos/usb3503_hkdk4212.c
@@ -0,0 +1,313 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics Co. Ltd
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <asm/arch/usb3503_hkdk4212.h>
+
+//[*]----------------------------------------------------------------------------------------------[*]
+// static function prototype
+//[*]----------------------------------------------------------------------------------------------[*]
+static void gpio_i2c_sda_port_control (unsigned char inout);
+static void gpio_i2c_clk_port_control (unsigned char inout);
+
+static unsigned char gpio_i2c_get_sda (void);
+void gpio_i2c_set_sda (unsigned char hi_lo);
+void gpio_i2c_set_clk (unsigned char hi_lo);
+
+static void gpio_i2c_start (void);
+static void gpio_i2c_stop (void);
+
+static void gpio_i2c_send_ack (void);
+static void gpio_i2c_send_noack (void);
+static unsigned char gpio_i2c_chk_ack (void);
+
+static void gpio_i2c_byte_write (unsigned char wdata);
+static void gpio_i2c_byte_read (unsigned char *rdata);
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static void delay_func(unsigned int us)
+{
+ unsigned long i;
+
+ for(i = 0; i < us; i++) { i++; i--; }
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static void gpio_i2c_sda_port_control (unsigned char inout)
+{
+ GPIO_I2C_SDA_CON_PORT &= (unsigned long)(~(GPIO_CON_PORT_MASK << (GPIO_SDA_PIN * GPIO_CON_PORT_OFFSET)));
+ GPIO_I2C_SDA_CON_PORT |= (unsigned long)( (inout << (GPIO_SDA_PIN * GPIO_CON_PORT_OFFSET)));
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static void gpio_i2c_clk_port_control (unsigned char inout)
+{
+ GPIO_I2C_CLK_CON_PORT &= (unsigned long)(~(GPIO_CON_PORT_MASK << (GPIO_CLK_PIN * GPIO_CON_PORT_OFFSET)));
+ GPIO_I2C_CLK_CON_PORT |= (unsigned long)( (inout << (GPIO_CLK_PIN * GPIO_CON_PORT_OFFSET)));
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static unsigned char gpio_i2c_get_sda (void)
+{
+ return GPIO_I2C_SDA_DAT_PORT & (HIGH << GPIO_SDA_PIN) ? 1 : 0;
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+void gpio_i2c_set_sda (unsigned char hi_lo)
+{
+ if(hi_lo) {
+ gpio_i2c_sda_port_control(GPIO_CON_INPUT);
+ delay_func(PORT_CHANGE_DELAY_TIME);
+ }
+ else {
+ GPIO_I2C_SDA_DAT_PORT &= ~(HIGH << GPIO_SDA_PIN);
+ gpio_i2c_sda_port_control(GPIO_CON_OUTPUT);
+ delay_func(PORT_CHANGE_DELAY_TIME);
+ }
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+void gpio_i2c_set_clk (unsigned char hi_lo)
+{
+ if(hi_lo) {
+ gpio_i2c_clk_port_control(GPIO_CON_INPUT);
+ delay_func(PORT_CHANGE_DELAY_TIME);
+ }
+ else {
+ GPIO_I2C_CLK_DAT_PORT &= ~(HIGH << GPIO_CLK_PIN);
+ gpio_i2c_clk_port_control(GPIO_CON_OUTPUT);
+ delay_func(PORT_CHANGE_DELAY_TIME);
+ }
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static void gpio_i2c_start (void)
+{
+ // Setup SDA, CLK output High
+ gpio_i2c_set_sda(HIGH);
+ gpio_i2c_set_clk(HIGH);
+
+ delay_func(DELAY_TIME);
+
+ // SDA low before CLK low
+ gpio_i2c_set_sda(LOW); delay_func(DELAY_TIME);
+ gpio_i2c_set_clk(LOW); delay_func(DELAY_TIME);
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static void gpio_i2c_stop (void)
+{
+ // Setup SDA, CLK output low
+ gpio_i2c_set_sda(LOW);
+ gpio_i2c_set_clk(LOW);
+
+ delay_func(DELAY_TIME);
+
+ // SDA high after CLK high
+ gpio_i2c_set_clk(HIGH); delay_func(DELAY_TIME);
+ gpio_i2c_set_sda(HIGH); delay_func(DELAY_TIME);
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static void gpio_i2c_send_ack (void)
+{
+ // SDA Low
+ gpio_i2c_set_sda(LOW); delay_func(DELAY_TIME);
+ gpio_i2c_set_clk(HIGH); delay_func(DELAY_TIME);
+ gpio_i2c_set_clk(LOW); delay_func(DELAY_TIME);
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static void gpio_i2c_send_noack (void)
+{
+ // SDA High
+ gpio_i2c_set_sda(HIGH); delay_func(DELAY_TIME);
+ gpio_i2c_set_clk(HIGH); delay_func(DELAY_TIME);
+ gpio_i2c_set_clk(LOW); delay_func(DELAY_TIME);
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static unsigned char gpio_i2c_chk_ack (void)
+{
+ unsigned char count = 0, ret = 0;
+
+ gpio_i2c_set_sda(LOW); delay_func(DELAY_TIME);
+ gpio_i2c_set_clk(HIGH); delay_func(DELAY_TIME);
+
+ gpio_i2c_sda_port_control(GPIO_CON_INPUT);
+ delay_func(PORT_CHANGE_DELAY_TIME);
+
+ while(gpio_i2c_get_sda()) {
+ if(count++ > 100) { ret = 1; break; }
+ else delay_func(DELAY_TIME);
+ }
+
+ gpio_i2c_set_clk(LOW); delay_func(DELAY_TIME);
+
+ if(ret) printf("gpio_i2c_chk_ack: no ack!!\n");
+ //else printf("gpio_i2c_chk_ack: ack!!\n");
+
+ return ret;
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static void gpio_i2c_byte_write (unsigned char wdata)
+{
+ unsigned char cnt, mask;
+
+ for(cnt = 0, mask = 0x80; cnt < 8; cnt++, mask >>= 1) {
+ if(wdata & mask) gpio_i2c_set_sda(HIGH);
+ else gpio_i2c_set_sda(LOW);
+
+ gpio_i2c_set_clk(HIGH); delay_func(DELAY_TIME);
+ gpio_i2c_set_clk(LOW); delay_func(DELAY_TIME);
+ }
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+static void gpio_i2c_byte_read (unsigned char *rdata)
+{
+ unsigned char cnt, mask;
+
+ gpio_i2c_sda_port_control(GPIO_CON_INPUT);
+ delay_func(PORT_CHANGE_DELAY_TIME);
+
+ for(cnt = 0, mask = 0x80, *rdata = 0; cnt < 8; cnt++, mask >>= 1) {
+ gpio_i2c_set_clk(HIGH); delay_func(DELAY_TIME);
+
+ if(gpio_i2c_get_sda()) *rdata |= mask;
+
+ gpio_i2c_set_clk(LOW); delay_func(DELAY_TIME);
+
+ }
+}
+
+#define MAX77686_ADDR (0x09 << 1)
+int max77686_write_reg(u8 reg, u8 *wdata, u8 wsize)
+{
+ unsigned char cnt, ack;
+
+ // start
+ gpio_i2c_start();
+
+ gpio_i2c_byte_write(MAX77686_ADDR + I2C_WRITE); // i2c address
+
+ if((ack = gpio_i2c_chk_ack())) goto write_stop;
+
+ gpio_i2c_byte_write(reg); // register
+
+ if((ack = gpio_i2c_chk_ack())) goto write_stop;
+
+ if(wsize) {
+ for(cnt = 0; cnt < wsize; cnt++) {
+ gpio_i2c_byte_write(wdata[cnt]);
+
+ if((ack = gpio_i2c_chk_ack())) goto write_stop;
+ }
+ }
+
+write_stop:
+
+ if(wsize) gpio_i2c_stop();
+
+ return ack;
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+int max77686_read_reg(u8 reg, u8 *rdata, u8 rsize)
+{
+ unsigned char ack, cnt;
+
+ // register pointer write
+ if(max77686_write_reg(reg, NULL, 0)) goto read_stop;
+
+ // restart
+ gpio_i2c_start();
+
+ gpio_i2c_byte_write(MAX77686_ADDR + I2C_READ); // i2c address
+
+ if((ack = gpio_i2c_chk_ack())) goto read_stop;
+
+ for(cnt=0; cnt < rsize; cnt++) {
+
+ gpio_i2c_byte_read(&rdata[cnt]);
+
+ if(cnt == rsize -1) gpio_i2c_send_noack();
+ else gpio_i2c_send_ack();
+ }
+
+read_stop:
+ gpio_i2c_stop();
+
+ return ack;
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+int usb3503_write (unsigned char reg, unsigned char *wdata, unsigned char wsize)
+{
+ unsigned char cnt, ack;
+
+ // start
+ gpio_i2c_start();
+
+ gpio_i2c_byte_write(USB3503_ADDR + I2C_WRITE); // i2c address
+
+ if((ack = gpio_i2c_chk_ack())) goto write_stop;
+
+ gpio_i2c_byte_write(reg); // register
+
+ if((ack = gpio_i2c_chk_ack())) goto write_stop;
+
+ if(wsize) {
+ for(cnt = 0; cnt < wsize; cnt++) {
+ gpio_i2c_byte_write(wdata[cnt]);
+
+ if((ack = gpio_i2c_chk_ack())) goto write_stop;
+ }
+ }
+
+write_stop:
+
+ if(wsize) gpio_i2c_stop();
+
+ return ack;
+}
+
+//[*]----------------------------------------------------------------------------------------------[*]
+int usb3503_read (unsigned char reg, unsigned char *rdata, unsigned char rsize)
+{
+ unsigned char ack, cnt;
+
+ // register pointer write
+ if(usb3503_write(reg, NULL, 0)) goto read_stop;
+
+ // restart
+ gpio_i2c_start();
+
+ gpio_i2c_byte_write(USB3503_ADDR + I2C_READ); // i2c address
+
+ if((ack = gpio_i2c_chk_ack())) goto read_stop;
+
+ for(cnt=0; cnt < rsize; cnt++) {
+
+ gpio_i2c_byte_read(&rdata[cnt]);
+
+ if(cnt == rsize -1) gpio_i2c_send_noack();
+ else gpio_i2c_send_ack();
+ }
+
+read_stop:
+ gpio_i2c_stop();
+
+ return ack;
+}
diff --git a/arch/arm/include/asm/arch-exynos/usb3503_hkdk4212.h b/arch/arm/include/asm/arch-exynos/usb3503_hkdk4212.h
new file mode 100644
index 0000000000..ba8c007048
--- /dev/null
+++ b/arch/arm/include/asm/arch-exynos/usb3503_hkdk4212.h
@@ -0,0 +1,83 @@
+/*
+ * (C) Copyright 2011 Samsung Electronics Co. Ltd
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 __USB3503_H__
+#define __USB3503_H__
+
+//[*]----------------------------------------------------------------------------------------------[*]
+#define USB3503_ADDR (0x08 << 1)
+
+#define USB3503_VIDL 0x00
+#define USB3503_VIDM 0x01
+#define USB3503_PIDL 0x02
+#define USB3503_PIDM 0x03
+#define USB3503_DIDL 0x04
+#define USB3503_DIDM 0x05
+
+#define USB3503_CFG1 0x06
+#define USB3503_SELF_BUS_PWR (1 << 7)
+
+#define USB3503_CFG2 0x07
+#define USB3503_CFG3 0x08
+#define USB3503_NRD 0x09
+
+#define USB3503_PDS 0x0a
+#define USB3503_PORT1 (1 << 1)
+#define USB3503_PORT2 (1 << 2)
+#define USB3503_PORT3 (1 << 3)
+#define USB3503_SP_ILOCK 0xe7
+#define USB3503_SPILOCK_CONNECT (1 << 1)
+#define USB3503_SPILOCK_CONFIG (1 << 0)
+
+#define USB3503_CFGP 0xee
+#define USB3503_CLKSUSP (1 << 7)
+
+//[*]----------------------------------------------------------------------------------------------[*]
+#define GPD1CON (*(volatile unsigned long *)(0x114000C0))
+#define GPD1DAT (*(volatile unsigned long *)(0x114000C4))
+#define GPD1PUD (*(volatile unsigned long *)(0x114000C8))
+
+//[*]----------------------------------------------------------------------------------------------[*]
+#define GPIO_I2C_SDA_CON_PORT GPD1CON
+#define GPIO_I2C_SDA_DAT_PORT GPD1DAT
+#define GPIO_SDA_PIN 0
+
+#define GPIO_I2C_CLK_CON_PORT GPD1CON
+#define GPIO_I2C_CLK_DAT_PORT GPD1DAT
+#define GPIO_CLK_PIN 1
+
+//[*]----------------------------------------------------------------------------------------------[*]
+#define DELAY_TIME 100 // us value
+#define PORT_CHANGE_DELAY_TIME 100
+
+#define GPIO_CON_PORT_MASK 0xF
+#define GPIO_CON_PORT_OFFSET 0x4
+
+#define GPIO_CON_INPUT 0x0
+#define GPIO_CON_OUTPUT 0x1
+
+//[*]----------------------------------------------------------------------------------------------[*]
+#define HIGH 1
+#define LOW 0
+
+#define I2C_READ 1
+#define I2C_WRITE 0
+//[*]----------------------------------------------------------------------------------------------[*]
+
+extern int usb3503_write (unsigned char reg, unsigned char *wdata, unsigned char wsize);
+extern int usb3503_read (unsigned char reg, unsigned char *rdata, unsigned char rsize);
+
+//[*]----------------------------------------------------------------------------------------------[*]
+#endif /*__USB3503_H__*/
+//[*]----------------------------------------------------------------------------------------------[*]
+//[*]----------------------------------------------------------------------------------------------[*]
+
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index df6a82854e..379c32a3f3 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -28,12 +28,26 @@
#include <malloc.h>
#include <watchdog.h>
#include <linux/compiler.h>
+#include <asm/arch/usb3503_hkdk4212.h>
#include "ehci.h"
/* Declare global data pointer */
DECLARE_GLOBAL_DATA_PTR;
+/*
+ * In 3.8 kernel the usb3503 is configured using i2c as follows:
+ * SP_ILOCK: set connect_n, config_n for config
+ * err = usb3503_write_register(i2c, USB3503_SP_ILOCK,
+ * (USB3503_SPILOCK_CONNECT
+ * | USB3503_SPILOCK_CONFIG));
+ * usb3503_set_bits(i2c, USB3503_CFG1, USB3503_SELF_BUS_PWR);
+ * usb3503_clear_bits(i2c, USB3503_SP_ILOCK,
+ * (USB3503_SPILOCK_CONNECT
+ * | USB3503_SPILOCK_CONFIG));
+ * We could try the same and see if storage enumerates consistently.
+ */
+
void max77686_update_reg(u8 reg, u8 val, u8 mask) {
u8 old_val, new_val;
@@ -202,6 +216,7 @@ u32 phypwr, phyclk, rstcon, a;
}
void usb_hub_init () {
+ u32 a, val, i2c_dat;
#define GPX3BASE ((void *) (0x11000C60))
@@ -225,6 +240,17 @@ void usb_hub_init () {
// Hub Wait RefClk stage
mdelay(10);
+ /* Configure the hub with i2c */
+ a = usb3503_read(USB3503_SP_ILOCK, &i2c_dat, (unsigned char) 1);
+ val = i2c_dat;
+ i2c_dat = i2c_dat | USB3503_SPILOCK_CONNECT | USB3503_SPILOCK_CONFIG;
+ a = usb3503_write(USB3503_SP_ILOCK, &i2c_dat, (unsigned char) 1);
+ i2c_dat = 0x80;
+ a = usb3503_write(USB3503_CFG1, &i2c_dat, (unsigned char) 1);
+
+ i2c_dat = i2c_dat & ~(USB3503_SPILOCK_CONNECT | USB3503_SPILOCK_CONFIG);
+ a = usb3503_write(USB3503_SP_ILOCK, &i2c_dat, (unsigned char) 1);
+
// Set CONNECT to 1 to move to hub configure phase.
gpio_set_value(GPX3BASE, 4, 1);
mdelay(10);