/*
Copyright 2018 Massdrop 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, see <http://www.gnu.org/licenses/>.
*/
#include "arm_atsam_protocol.h"
#include <string.h>
Usb2422 USB2422_shadow;
unsigned char i2c0_buf[34];
const uint16_t MFRNAME[] = { 'M','a','s','s','d','r','o','p',' ','I','n','c','.' }; //Massdrop Inc.
const uint16_t PRDNAME[] = { 'M','a','s','s','d','r','o','p',' ','H','u','b' }; //Massdrop Hub
#ifndef MD_BOOTLOADER
//Serial number reported stops before first found space character or at last found character
const uint16_t SERNAME[] = { 'U','n','a','v','a','i','l','a','b','l','e' }; //Unavailable
#else
//In production, this field is found, modified, and offset noted as the last 32-bit word in the bootloader space
//The offset allows the application to use the factory programmed serial (which may differ from the physical serial label)
//Serial number reported stops before first found space character or when max size is reached
__attribute__((__aligned__(4)))
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' };
//NOTE: Serial replacer will not write a string longer than given here as a precaution, so give enough
// space as needed and adjust BOOTLOADER_SERIAL_MAX_SIZE to match amount given
#endif //MD_BOOTLOADER
uint8_t usb_host_port;
#ifndef MD_BOOTLOADER
uint8_t usb_extra_state;
uint8_t usb_extra_manual;
uint8_t usb_gcr_auto;
#endif //MD_BOOTLOADER
uint16_t adc_extra;
void USB_write2422_block(void)
{
unsigned char *dest = i2c0_buf;
unsigned char *src;
unsigned char *base = (unsigned char *)&USB2422_shadow;
DBGC(DC_USB_WRITE2422_BLOCK_BEGIN);
for (src = base; src < base + 256; src += 32)
{
dest[0] = src - base;
dest[1] = 32;
memcpy(&dest[2], src, 32);
i2c0_transmit(USB2422_ADDR, dest, 34, 50000);
SERCOM0->I2CM.CTRLB.bit.CMD = 0x03;
while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_USB_WRITE2422_BLOCK_SYNC_SYSOP); }
CLK_delay_us(100);
}
DBGC(DC_USB_WRITE2422_BLOCK_COMPLETE);
}
void USB2422_init(void)
{
Gclk *pgclk = GCLK;
Mclk *pmclk = MCLK;
Port *pport = PORT;
Oscctrl *posc = OSCCTRL;
Usb *pusb = USB;
Srdata_t *pspi = &srdata;
DBGC(DC_USB2422_INIT_BEGIN);
while ((v_5v = adc_get(ADC_5V)) < ADC_5V_START_LEVEL) { DBGC(DC_USB2422_INIT_WAIT_5V_LOW); }
//setup peripheral and synchronous bus clocks to USB
pgclk->PCHCTRL[10].bit.GEN = 0;
pgclk->PCHCTRL[10].bit.CHEN = 1;
pmclk->AHBMASK.bit.USB_ = 1;
pmclk->APBBMASK.bit.USB_ = 1;
//setup port pins for D-, D+, and SOF_1KHZ
pport->Group[0].PMUX[12].reg = 0x77; //PA24, PA25, function column H for USB D-, D+
pport->Group[0].PINCFG[24].bit.PMUXEN = 1;
pport->Group[0].PINCFG[25].bit.PMUXEN = 1;
pport->Group[1].PMUX[11].bit.PMUXE = 7; //PB22, function column H for USB SOF_1KHz output
pport->Group[1].PINCFG[22].bit.PMUXEN = 1;
//configure and enable DFLL for USB clock recovery mode at 48MHz
posc->DFLLCTRLA.bit.ENABLE = 0;
while (posc->DFLLSYNC.bit.ENABLE) { DBGC(DC_USB2422_INIT_OSC_SYNC_DISABLING); }
while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_1); }
posc->DFLLCTRLB.bit.USBCRM = 1;
while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_2); }
posc->DFLLCTRLB.bit.MODE = 1;
while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_3); }
posc->DFLLCTRLB.bit.QLDIS = 0;
while (posc->DFLLSYNC.bit.DFLLCTRLB) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_4); }
posc->DFLLCTRLB.bit.CCDIS = 1;
posc->DFLLMUL.bit.MUL = 0xBB80; //4800 x 1KHz
while (posc->DFLLSYNC.bit.DFLLMUL) { DBGC(DC_USB2422_INIT_OSC_SYNC_DFLLMUL); }
posc->DFLLCTRLA.bit.ENABLE = 1;
while (posc->DFLLSYNC.bit.ENABLE) { DBGC(DC_USB2422_INIT_OSC_SYNC_ENABLING); }
pusb->DEVICE.CTRLA.bit.SWRST = 1;
while (pusb->DEVICE.SYNCBUSY.bit.SWRST) { DBGC(DC_USB2422_INIT_USB_SYNC_SWRST); }
while (pusb->DEVICE.CTRLA.bit.SWRST) { DBGC(DC_USB2422_INIT_USB_WAIT_SWRST); }
//calibration from factory presets
pusb->DEVICE.PADCAL.bit.TRANSN = (USB_FUSES_TRANSN_ADDR >> USB_FUSES_TRANSN_Pos) & USB_FUSES_TRANSN_Msk;
pusb->DEVICE.PADCAL.bit.TRANSP = (USB_FUSES_TRANSP_ADDR >> USB_FUSES_TRANSP_Pos) & USB_FUSES_TRANSP_Msk;
pusb->DEVICE.PADCAL.bit.TRIM = (USB_FUSES_TRIM_ADDR >> USB_FUSES_TRIM_Pos) & USB_FUSES_TRIM_Msk;
//device mode, enabled
pusb->DEVICE.CTRLB.bit.SPDCONF = 0; //full speed
pusb->DEVICE.CTRLA.bit.MODE = 0;
pusb->DEVICE