1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13/**
14 * @brief Microchip USB3503 USB 2.0 hub controller
15 * @see http://www.microchip.com/wwwproducts/en/USB3503
16 */
17
18#include <usb/drivers/usb3503_hub.h>
19#include "../../../services.h"
20
21#define REG_VIDL         0x00
22#define REG_VIDM         0x01
23#define REG_PIDL         0x02
24#define REG_PIDM         0x03
25#define REG_DIDL         0x04
26#define REG_DIDM         0x05
27#define REG_CFG1         0x06
28#define REG_CFG2         0x07
29#define REG_CFG3         0x08
30#define REG_NRD          0x09
31#define REG_PDS          0x0A
32#define REG_PDB          0x0B
33#define REG_MAXPS        0x0C
34#define REG_MAXPB        0x0D
35#define REG_HCMCS        0x0E
36#define REG_HCMCB        0x0F
37#define REG_PWRT         0x10
38#define REG_LANG_ID_H    0x11
39#define REG_LANG_ID_L    0x12
40#define REG_MFR_STR_LEN  0x13
41#define REG_PRD_STR_LEN  0x14
42#define REG_SER_STR_LEN  0x15
43#define REG_MFR_STR      0x16
44#define REG_PROD_STR     0x54
45#define REG_SER_STR      0x92
46#define REG_BC_EN        0xD0
47#define REG_PRTPWR       0xE5
48#define REG_OCS          0xE6
49#define REG_SP_ILOCK     0xE7
50#define REG_INT_STATUS   0xE8
51#define REG_INT_MASK     0xE9
52#define REG_CFGP         0xEE
53#define REG_VSNSUP3      0xF4
54#define REG_VSNS21       0xF5
55#define REG_BSTUP3       0xF6
56#define REG_BST21        0xF8
57#define REG_PRTSP        0xFA
58#define REG_PRTR12       0xFB
59#define REG_PRTR34       0xFC
60#define REG_STCD         0xFF
61
62static int read_reg(usb3503_t *hub, int addr)
63{
64	int count;
65	char data;
66	count = i2c_kvslave_read(&hub->kvslave, addr, &data, 1);
67	if (count != 1) {
68		return -1;
69	} else {
70		return data;
71	}
72}
73
74static int write_reg(usb3503_t *hub, int addr, int data)
75{
76	int count;
77	char cdata;
78	cdata = data;
79	count = i2c_kvslave_write(&hub->kvslave, addr, &cdata, 1);
80	if (count != 1) {
81		return -1;
82	} else {
83		return 0;
84	}
85}
86
87int
88usb3503_init(i2c_bus_t *i2c_bus, gpio_sys_t *gpio_sys, gpio_id_t o_nreset,
89	     gpio_id_t o_hubconnect, gpio_id_t i_nint, usb3503_t *hub)
90{
91	if (i2c_slave_init
92	    (i2c_bus, USB3503_I2C_ADDR, I2C_SLAVE_ADDR_7BIT, I2C_SLAVE_SPEED_FAST, 0, &hub->i2c_slave)) {
93        ZF_LOGE("Failed to intialize slave handle.");
94		return -1;
95	}
96    if (i2c_kvslave_init(&hub->i2c_slave, BIG8, BIG8, &hub->kvslave)) {
97        ZF_LOGE("Failed to initialize lib KV-Slave instance handle.");
98        return -1;
99    }
100	if (gpio_new(gpio_sys, o_nreset, GPIO_DIR_OUT, &hub->o_nreset)) {
101		return -1;
102	}
103	if (gpio_new(gpio_sys, o_hubconnect, GPIO_DIR_OUT, &hub->o_hubconnect)) {
104		return -1;
105	}
106	if (gpio_new(gpio_sys, i_nint, GPIO_DIR_OUT, &hub->i_nint)) {
107		return -1;
108	}
109	/* Turn off the HUB */
110	gpio_clr(&hub->o_nreset);
111	gpio_clr(&hub->o_hubconnect);
112
113	/* Select Primary or Secondary reference clock
114	 * Primary reference clock freq (NINT high during init)
115	 * SEL -> FREQ
116	 * 00  -> 38.4 MHz
117	 * 01  -> 26.0 MHz
118	 * 10  -> 19.2 MHz
119	 * 11  -> 12.0 MHz
120	 *
121	 * Secondary reference clock freq (NINT low during init)
122	 * SEL -> FREQ
123	 * 00  -> 24.0 MHz
124	 * 01  -> 27.0 MHz
125	 * 10  -> 25.0 MHz
126	 * 11  -> 50.0 MHz
127	 *
128	 * Known platforms:
129	 * Odroid - SEL = 00
130	 */
131	gpio_clr(&hub->i_nint);
132	/* TODO set clock frequency */
133
134	/* Start the init process */
135	gpio_set(&hub->o_nreset);
136	return 0;
137}
138
139void usb3503_reset(usb3503_t *hub)
140{
141	write_reg(hub, REG_STCD, BIT(1));
142}
143
144void usb3503_hard_reset(usb3503_t *hub)
145{
146	gpio_clr(&hub->o_nreset);
147	ps_udelay(100);
148	gpio_set(&hub->o_nreset);
149}
150
151void usb3503_connect(usb3503_t *hub)
152{
153	gpio_set(&hub->o_hubconnect);
154}
155
156void usb3503_disconnect(usb3503_t *hub)
157{
158	gpio_clr(&hub->o_hubconnect);
159}
160
161void usb3503_handle_irq(usb3503_t *hub)
162{
163	uint8_t status, mask;
164	status = read_reg(hub, REG_INT_STATUS);
165	mask = read_reg(hub, REG_INT_MASK);
166	printf("HUB IRQ status: 0x%02x/0x%02x\n", status, mask);
167}
168
169