]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/protocol/arm_atsam/usb/usb2422.c
7c78e41d49ab95d6d03fb7402a8ad80c6a1ed19c
[qmk_firmware.git] / tmk_core / protocol / arm_atsam / usb / usb2422.c
1 /*
2 Copyright 2018 Massdrop Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "arm_atsam_protocol.h"
19 #include <string.h>
20
21 Usb2422 USB2422_shadow;
22 unsigned char i2c0_buf[34];
23
24 const uint16_t MFRNAME[] = { 'M','a','s','s','d','r','o','p',' ','I','n','c','.' }; //Massdrop Inc.
25 const uint16_t PRDNAME[] = { 'M','a','s','s','d','r','o','p',' ','H','u','b' }; //Massdrop Hub
26 #ifndef MD_BOOTLOADER
27 //Serial number reported stops before first found space character or at last found character
28 const uint16_t SERNAME[] = { 'U','n','a','v','a','i','l','a','b','l','e' }; //Unavailable
29 #else
30 //In production, this field is found, modified, and offset noted as the last 32-bit word in the bootloader space
31 //The offset allows the application to use the factory programmed serial (which may differ from the physical serial label)
32 //Serial number reported stops before first found space character or when max size is reached
33 __attribute__((__aligned__(4)))
34 const uint16_t SERNAME[BOOTLOADER_SERIAL_MAX_SIZE] = { 'M','D','H','U','B','B','O','O','T','L','0','0','0','0','0','0','0','0','0','0' };
35 //NOTE: Serial replacer will not write a string longer than given here as a precaution, so give enough
36 //      space as needed and adjust BOOTLOADER_SERIAL_MAX_SIZE to match amount given
37 #endif //MD_BOOTLOADER
38
39 uint8_t usb_host_port;
40
41 #ifndef MD_BOOTLOADER
42
43 uint8_t usb_extra_state;
44 uint8_t usb_extra_manual;
45 uint8_t usb_gcr_auto;
46
47 #endif //MD_BOOTLOADER
48
49 uint16_t adc_extra;
50
51 void USB_write2422_block(void)
52 {
53     unsigned char *dest = i2c0_buf;
54     unsigned char *src;
55     unsigned char *base = (unsigned char *)&USB2422_shadow;
56
57     DBGC(DC_USB_WRITE2422_BLOCK_BEGIN);
58
59     for (src =  base; src < base + 256; src += 32)
60     {
61         dest[0] = src - base;
62         dest[1] = 32;
63         memcpy(&dest[2], src, 32);
64         i2c0_transmit(USB2422_ADDR, dest, 34, 50000);
65         SERCOM0->I2CM.CTRLB.bit.CMD = 0x03;
66         while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_USB_WRITE2422_BLOCK_SYNC_SYSOP); }
67         CLK_delay_us(100);
68     }
69
70     DBGC(DC_USB_WRITE2422_BLOCK_COMPLETE);
71 }
72
73 void USB2422_init(void)
74 {
75     Gclk *pgclk = GCLK;
76     Mclk *pmclk = MCLK;
77     Port *pport = PORT;
78     Oscctrl *posc = OSCCTRL;
79     Usb *pusb = USB;
80     Srdata_t *pspi = &srdata;
81
82     DBGC(DC_USB2422_INIT_BEGIN);
83
84     while ((v_5v = adc_get(ADC_5V)) < ADC_5V_START_LEVEL) { DBGC(DC_USB2422_INIT_WAIT_5V_LOW); }
85
86     //setup peripheral and synchronous bus clocks to USB
87     pgclk->PCHCTRL[10].bit.GEN = 0;
88     pgclk->PCHCTRL[10].bit.CHEN = 1;
89     pmclk->AHBMASK.bit.USB_ = 1;
90     pmclk->APBBMASK.bit.USB_ = 1;
91
92     //setup port pins for D-, D+, and SOF_1KHZ
93     pport->Group[0].PMUX[12].reg = 0x77; //PA24, PA25, function column H for USB D-, D+
94     pport->Group[0].PINCFG[24].bit.PMUXEN = 1;
95     pport->Group[0].PINCFG[25].bit.PMUXEN = 1;
96     pport->Group[1].PMUX[11].bit.PMUXE = 7; //PB22, function column H for USB SOF_1KHz output
97     pport->Group[1].PINCFG[22].bit.PMUXEN = 1;
98
99     //configure and enable DFLL for USB clock recovery mode at 48MHz
100     posc->DFLLCTRLA.bit.ENABLE = 0;
101     while (posc->DFLLSYNC.bit.ENABLE) { DBGC(DC_USB2422_INIT_OSC_SYNC_DISABLING); }
102     while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_1); }
103     posc->DFLLCTRLB.bit.USBCRM = 1;
104     while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_2); }
105     posc->DFLLCTRLB.bit.MODE = 1;
106     while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_3); }
107     posc->DFLLCTRLB.bit.QLDIS = 0;
108     while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_4); }
109     posc->DFLLCTRLB.bit.CCDIS = 1;
110     posc->DFLLMUL.bit.MUL = 0xBB80; //4800 x 1KHz
111     while (posc->DFLLSYNC.bit.DFLLMUL) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLMUL); }
112     posc->DFLLCTRLA.bit.ENABLE = 1;
113     while (posc->DFLLSYNC.bit.ENABLE) { DBGC(DC_USB2422_INIT_OSC_SYNC_ENABLING); }
114
115     pusb->DEVICE.CTRLA.bit.SWRST = 1;
116     while (pusb->DEVICE.SYNCBUSY.bit.SWRST) { DBGC(DC_USB2422_INIT_USB_SYNC_SWRST); }
117     while (pusb->DEVICE.CTRLA.bit.SWRST) { DBGC(DC_USB2422_INIT_USB_WAIT_SWRST); }
118     //calibration from factory presets
119     pusb->DEVICE.PADCAL.bit.TRANSN = (USB_FUSES_TRANSN_ADDR >> USB_FUSES_TRANSN_Pos) & USB_FUSES_TRANSN_Msk;
120     pusb->DEVICE.PADCAL.bit.TRANSP = (USB_FUSES_TRANSP_ADDR >> USB_FUSES_TRANSP_Pos) & USB_FUSES_TRANSP_Msk;
121     pusb->DEVICE.PADCAL.bit.TRIM = (USB_FUSES_TRIM_ADDR >> USB_FUSES_TRIM_Pos) & USB_FUSES_TRIM_Msk;
122     //device mode, enabled
123     pusb->DEVICE.CTRLB.bit.SPDCONF = 0; //full speed
124     pusb->DEVICE.CTRLA.bit.MODE = 0;
125     pusb->DEVICE.CTRLA.bit.ENABLE = 1;
126     while (pusb->DEVICE.SYNCBUSY.bit.ENABLE) { DBGC(DC_USB2422_INIT_USB_SYNC_ENABLING); }
127
128     pusb->DEVICE.QOSCTRL.bit.DQOS = 2;
129     pusb->DEVICE.QOSCTRL.bit.CQOS = 2;
130
131     pport->Group[USB2422_HUB_ACTIVE_GROUP].PINCFG[USB2422_HUB_ACTIVE_PIN].bit.INEN = 1;
132
133     i2c0_init(); //IC2 clk must be high at USB2422 reset release time to signal SMB configuration
134
135     pspi->bit.HUB_CONNECT = 1; //connect signal
136     pspi->bit.HUB_RESET_N = 1; //reset high
137     SPI_WriteSRData();
138
139     CLK_delay_us(100);
140
141 #ifndef MD_BOOTLOADER
142
143     usb_extra_manual = 0;
144     usb_gcr_auto = 1;
145
146 #endif //MD_BOOTLOADER
147
148     DBGC(DC_USB2422_INIT_COMPLETE);
149 }
150
151 void USB_reset(void)
152 {
153     Srdata_t *pspi = &srdata;
154
155     DBGC(DC_USB_RESET_BEGIN);
156
157     //pulse reset for at least 1 usec
158     pspi->bit.HUB_RESET_N = 0; //reset low
159     SPI_WriteSRData();
160     CLK_delay_us(1);
161     pspi->bit.HUB_RESET_N = 1; //reset high to run
162     SPI_WriteSRData();
163     CLK_delay_us(1);
164
165     DBGC(DC_USB_RESET_COMPLETE);
166 }
167
168 void USB_configure(void)
169 {
170     Usb2422 *pusb2422 = &USB2422_shadow;
171     memset(pusb2422, 0, sizeof(Usb2422));
172
173     uint16_t *serial_use = (uint16_t *)SERNAME; //Default to use SERNAME from this file
174     uint8_t serial_length = sizeof(SERNAME) / sizeof(uint16_t); //Default to use SERNAME from this file
175 #ifndef MD_BOOTLOADER
176     uint32_t serial_ptrloc = (uint32_t)&_srom - 4;
177 #else //MD_BOOTLOADER
178     uint32_t serial_ptrloc = (uint32_t)&_erom - 4;
179 #endif //MD_BOOTLOADER
180     uint32_t serial_address = *(uint32_t *)serial_ptrloc; //Address of bootloader's serial number if available
181
182     DBGC(DC_USB_CONFIGURE_BEGIN);
183
184     if (serial_address != 0xFFFFFFFF && serial_address < serial_ptrloc) //Check for factory programmed serial address
185     {
186         if ((serial_address & 0xFF) % 4 == 0) //Check alignment
187         {
188             serial_use = (uint16_t *)(serial_address);
189             serial_length = 0;
190             while ((*(serial_use + serial_length) > 32 && *(serial_use + serial_length) < 127) &&
191                    serial_length < BOOTLOADER_SERIAL_MAX_SIZE)
192             {
193                 serial_length++;
194                 DBGC(DC_USB_CONFIGURE_GET_SERIAL);
195             }
196         }
197     }
198
199     //configure Usb2422 registers
200     pusb2422->VID.reg = 0x04D8; // from Microchip 4/19/2018
201     pusb2422->PID.reg = 0xEEC5; // from Microchip 4/19/2018 = Massdrop, Inc. USB Hub
202     pusb2422->DID.reg = 0x0101; // BCD 01.01
203     pusb2422->CFG1.bit.SELF_BUS_PWR = 1; // self powered for now
204     pusb2422->CFG1.bit.HS_DISABLE = 1; // full or high speed
205     //pusb2422->CFG2.bit.COMPOUND = 0; // compound device
206     pusb2422->CFG3.bit.STRING_EN = 1; // strings enabled
207     //pusb2422->NRD.bit.PORT2_NR = 0; // MCU is non-removable
208     pusb2422->MAXPB.reg = 20; // 0mA
209     pusb2422->HCMCB.reg = 20; // 0mA
210     pusb2422->MFRSL.reg = sizeof(MFRNAME) / sizeof(uint16_t);
211     pusb2422->PRDSL.reg = sizeof(PRDNAME) / sizeof(uint16_t);
212     pusb2422->SERSL.reg = serial_length;
213     memcpy(pusb2422->MFRSTR, MFRNAME, sizeof(MFRNAME));
214     memcpy(pusb2422->PRDSTR, PRDNAME, sizeof(PRDNAME));
215     memcpy(pusb2422->SERSTR, serial_use, serial_length * sizeof(uint16_t));
216     //pusb2422->BOOSTUP.bit.BOOST=3;    //upstream port
217     //pusb2422->BOOSTDOWN.bit.BOOST1=0; // extra port
218     //pusb2422->BOOSTDOWN.bit.BOOST2=2; //MCU is close
219     pusb2422->STCD.bit.USB_ATTACH = 1;
220     USB_write2422_block();
221
222     adc_extra = 0;
223
224     DBGC(DC_USB_CONFIGURE_COMPLETE);
225 }
226
227 uint16_t USB_active(void)
228 {
229     return (PORT->Group[USB2422_HUB_ACTIVE_GROUP].IN.reg & (1 << USB2422_HUB_ACTIVE_PIN)) != 0;
230 }
231
232 void USB_set_host_by_voltage(void)
233 {
234     //UP is upstream device (HOST)
235     //DN1 is downstream device (EXTRA)
236     //DN2 is keyboard (KEYB)
237
238     DBGC(DC_USB_SET_HOST_BY_VOLTAGE_BEGIN);
239
240     usb_host_port = USB_HOST_PORT_UNKNOWN;
241 #ifndef MD_BOOTLOADER
242     usb_extra_state = USB_EXTRA_STATE_UNKNOWN;
243 #endif //MD_BOOTLOADER
244     srdata.bit.SRC_1 = 1;       //USBC-1 available for test
245     srdata.bit.SRC_2 = 1;       //USBC-2 available for test
246     srdata.bit.E_UP_N = 1;      //HOST disable
247     srdata.bit.E_DN1_N = 1;     //EXTRA disable
248     srdata.bit.E_VBUS_1 = 0;    //USBC-1 disable full power I/O
249     srdata.bit.E_VBUS_2 = 0;    //USBC-2 disable full power I/O
250
251     SPI_WriteSRData();
252
253     CLK_delay_ms(250);
254
255     while ((v_5v = adc_get(ADC_5V)) < ADC_5V_START_LEVEL) { DBGC(DC_USB_SET_HOST_5V_LOW_WAITING); }
256
257     v_con_1 = adc_get(ADC_CON1);
258     v_con_2 = adc_get(ADC_CON2);
259
260     v_con_1_boot = v_con_1;
261     v_con_2_boot = v_con_2;
262
263     if (v_con_1 > v_con_2)
264     {
265         srdata.bit.S_UP = 0;        //HOST to USBC-1
266         srdata.bit.S_DN1 = 1;       //EXTRA to USBC-2
267         srdata.bit.SRC_1 = 1;       //HOST on USBC-1
268         srdata.bit.SRC_2 = 0;       //EXTRA available on USBC-2
269
270         srdata.bit.E_VBUS_1 = 1;    //USBC-1 enable full power I/O
271         srdata.bit.E_VBUS_2 = 0;    //USBC-2 disable full power I/O
272
273         SPI_WriteSRData();
274
275         srdata.bit.E_UP_N = 0;      //HOST enable
276
277         SPI_WriteSRData();
278
279         usb_host_port = USB_HOST_PORT_1;
280     }
281     else
282     {
283         srdata.bit.S_UP = 1;        //EXTRA to USBC-1
284         srdata.bit.S_DN1 = 0;       //HOST to USBC-2
285         srdata.bit.SRC_1 = 0;       //EXTRA available on USBC-1
286         srdata.bit.SRC_2 = 1;       //HOST on USBC-2
287
288         srdata.bit.E_VBUS_1 = 0;    //USBC-1 disable full power I/O
289         srdata.bit.E_VBUS_2 = 1;    //USBC-2 enable full power I/O
290
291         SPI_WriteSRData();
292
293         srdata.bit.E_UP_N = 0;      //HOST enable
294
295         SPI_WriteSRData();
296
297         usb_host_port = USB_HOST_PORT_2;
298     }
299
300 #ifndef MD_BOOTLOADER
301     usb_extra_state = USB_EXTRA_STATE_DISABLED;
302 #endif //MD_BOOTLOADER
303
304     USB_reset();
305     USB_configure();
306
307     DBGC(DC_USB_SET_HOST_BY_VOLTAGE_COMPLETE);
308 }
309
310 uint8_t USB2422_Port_Detect_Init(void)
311 {
312     uint32_t port_detect_retry_ms;
313     uint32_t tmod;
314
315     DBGC(DC_PORT_DETECT_INIT_BEGIN);
316
317     USB_set_host_by_voltage();
318
319     port_detect_retry_ms = CLK_get_ms() + PORT_DETECT_RETRY_INTERVAL;
320
321     while (!USB_active())
322     {
323         tmod = CLK_get_ms() % PORT_DETECT_RETRY_INTERVAL;
324
325         if (v_con_1 > v_con_2) //Values updated from USB_set_host_by_voltage();
326         {
327             //1 flash for port 1 detected
328             if (tmod > 500 && tmod < 600) { led_on; }
329             else { led_off; }
330         }
331         else if (v_con_2 > v_con_1) //Values updated from USB_set_host_by_voltage();
332         {
333             //2 flash for port 2 detected
334             if (tmod > 500 && tmod < 600) { led_on; }
335             else if (tmod > 700 && tmod < 800) { led_on; }
336             else { led_off; }
337         }
338
339         if (CLK_get_ms() > port_detect_retry_ms)
340         {
341             DBGC(DC_PORT_DETECT_INIT_FAILED);
342             return 0;
343         }
344     }
345
346     DBGC(DC_PORT_DETECT_INIT_COMPLETE);
347
348     return 1;
349 }
350
351 #ifndef MD_BOOTLOADER
352
353 void USB_ExtraSetState(uint8_t state)
354 {
355     uint8_t state_save = state;
356
357     if (state == USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG)
358         state = USB_EXTRA_STATE_DISABLED;
359
360     if (usb_host_port == USB_HOST_PORT_1) srdata.bit.E_VBUS_2 = state;
361     else if (usb_host_port == USB_HOST_PORT_2) srdata.bit.E_VBUS_1 = state;
362     else return;
363
364     srdata.bit.E_DN1_N = !state;
365     SPI_WriteSRData();
366
367     usb_extra_state = state_save;
368
369     if (usb_extra_state == USB_EXTRA_STATE_ENABLED) CDC_print("USB: Extra enabled\r\n");
370     else if (usb_extra_state == USB_EXTRA_STATE_DISABLED)
371     {
372       CDC_print("USB: Extra disabled\r\n");
373       if (led_animation_breathing) gcr_breathe = gcr_desired;
374     }
375     else if (usb_extra_state == USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG) CDC_print("USB: Extra disabled until replug\r\n");
376     else CDC_print("USB: Extra state unknown\r\n");
377 }
378
379 void USB_HandleExtraDevice(void)
380 {
381     uint16_t adcval;
382
383     if (usb_host_port == USB_HOST_PORT_1) adcval = adc_get(ADC_CON2);
384     else if (usb_host_port == USB_HOST_PORT_2) adcval = adc_get(ADC_CON1);
385     else return;
386
387     adc_extra = adc_extra * 0.9 + adcval * 0.1;
388
389     //Check for a forced disable state (such as overload prevention)
390     if (usb_extra_state == USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG)
391     {
392         //Detect unplug and reset state to disabled
393         if (adc_extra > USB_EXTRA_ADC_THRESHOLD) usb_extra_state = USB_EXTRA_STATE_DISABLED;
394
395         return; //Return even if unplug detected
396     }
397
398     if (usb_extra_manual)
399     {
400         if (usb_extra_state == USB_EXTRA_STATE_DISABLED)
401         USB_ExtraSetState(USB_EXTRA_STATE_ENABLED);
402
403         return;
404     }
405
406     //dpf("a %i %i\r\n",adcval, adc_extra);
407     if (usb_extra_state == USB_EXTRA_STATE_DISABLED && adc_extra < USB_EXTRA_ADC_THRESHOLD) USB_ExtraSetState(USB_EXTRA_STATE_ENABLED);
408     else if (usb_extra_state == USB_EXTRA_STATE_ENABLED && adc_extra > USB_EXTRA_ADC_THRESHOLD) USB_ExtraSetState(USB_EXTRA_STATE_DISABLED);
409 }
410
411 #endif //MD_BOOTLOADER
412