forked from len0rd/rockbox
Add Xuelin iHIFI 770/770C/800 support
Taken from the xvortex fork (Roman Stolyarov) Ported, rebased, and cleaned up by myself. Change-Id: I7b2bca2d29502f2e4544e42f3d122786dd4b7978
This commit is contained in:
parent
af9459a799
commit
d4942cc74c
95 changed files with 4419 additions and 534 deletions
|
|
@ -75,6 +75,13 @@ static const unsigned short lin_brightness[] = {
|
|||
759, 768, 778, 788, 800, 812, 826, 841,
|
||||
856, 873, 891, 910, 931, 952, 975, 1000
|
||||
};
|
||||
#elif defined(IHIFI770) || defined(IHIFI770C) || defined(IHIFI800)
|
||||
static const unsigned short lin_brightness[] = {
|
||||
4096, 4215, 4381, 4603, 4887, 5243, 5679, 6201,
|
||||
6818, 7538, 8370, 9320, 10397, 11609, 12963, 14469,
|
||||
16133, 17963, 19968, 22156, 24534, 27110, 29893, 32890,
|
||||
36109, 39559, 43246, 47180, 51368, 55817, 60537, 65535
|
||||
};
|
||||
#endif
|
||||
|
||||
bool backlight_hw_init(void)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#elif defined(HM60X) || defined(HM801) || (CONFIG_KEYPAD == MA_PAD) || \
|
||||
(CONFIG_KEYPAD == IHIFI_PAD)
|
||||
#define DEBUG_CANCEL BUTTON_LEFT
|
||||
#elif (CONFIG_KEYPAD == IHIFI_770_PAD) || (CONFIG_KEYPAD == IHIFI_800_PAD)
|
||||
#define DEBUG_CANCEL BUTTON_POWER
|
||||
#endif
|
||||
|
||||
/* Skeleton for adding target specific debug info to the debug menu
|
||||
|
|
|
|||
88
firmware/target/arm/rk27xx/ihifi2/audio-ihifi770.c
Normal file
88
firmware/target/arm/rk27xx/ihifi2/audio-ihifi770.c
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "audiohw.h"
|
||||
|
||||
void wm8740_hw_init(void)
|
||||
{
|
||||
GPIO_PADR &= ~(1<<0); /* MD */
|
||||
GPIO_PACON |= (1<<0);
|
||||
|
||||
GPIO_PADR &= ~(1<<1); /* MC */
|
||||
GPIO_PACON |= (1<<1);
|
||||
|
||||
SCU_IOMUXB_CON &= ~(1<<2);
|
||||
GPIO_PCDR |= (1<<4); /* ML */
|
||||
GPIO_PCCON |= (1<<4);
|
||||
}
|
||||
|
||||
void wm8740_set_md(const int val)
|
||||
{
|
||||
if (val)
|
||||
GPIO_PADR |= (1<<0);
|
||||
else
|
||||
GPIO_PADR &= ~(1<<0);
|
||||
}
|
||||
|
||||
void wm8740_set_mc(const int val)
|
||||
{
|
||||
if (val)
|
||||
GPIO_PADR |= (1<<1);
|
||||
else
|
||||
GPIO_PADR &= ~(1<<1);
|
||||
}
|
||||
|
||||
void wm8740_set_ml(const int val)
|
||||
{
|
||||
if (val)
|
||||
GPIO_PCDR |= (1<<4);
|
||||
else
|
||||
GPIO_PCDR &= ~(1<<4);
|
||||
}
|
||||
|
||||
static void pop_ctrl(const int val)
|
||||
{
|
||||
if (val)
|
||||
GPIO_PADR |= (1<<7);
|
||||
else
|
||||
GPIO_PADR &= ~(1<<7);
|
||||
}
|
||||
|
||||
void audiohw_postinit(void)
|
||||
{
|
||||
pop_ctrl(0);
|
||||
sleep(HZ/4);
|
||||
wm8740_hw_init();
|
||||
audiohw_init();
|
||||
sleep(HZ/2);
|
||||
pop_ctrl(1);
|
||||
sleep(HZ/4);
|
||||
audiohw_unmute();
|
||||
}
|
||||
|
||||
void audiohw_close(void)
|
||||
{
|
||||
audiohw_mute();
|
||||
pop_ctrl(0);
|
||||
sleep(HZ/4);
|
||||
}
|
||||
67
firmware/target/arm/rk27xx/ihifi2/audio-ihifi800.c
Normal file
67
firmware/target/arm/rk27xx/ihifi2/audio-ihifi800.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "audiohw.h"
|
||||
#include "i2c-rk27xx.h"
|
||||
|
||||
#define ES9018_I2C_ADDR 0x90
|
||||
|
||||
static unsigned char buf;
|
||||
|
||||
void es9018_write_reg(uint8_t reg, uint8_t val)
|
||||
{
|
||||
buf = val;
|
||||
i2c_write(ES9018_I2C_ADDR, reg, sizeof(buf), (void*)&buf);
|
||||
}
|
||||
|
||||
uint8_t es9018_read_reg(uint8_t reg)
|
||||
{
|
||||
i2c_read(ES9018_I2C_ADDR, reg, sizeof(buf), (void*)&buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void pop_ctrl(const int val)
|
||||
{
|
||||
if (val)
|
||||
GPIO_PADR |= (1<<7);
|
||||
else
|
||||
GPIO_PADR &= ~(1<<7);
|
||||
}
|
||||
|
||||
void audiohw_postinit(void)
|
||||
{
|
||||
pop_ctrl(0);
|
||||
sleep(HZ/4);
|
||||
audiohw_init();
|
||||
sleep(HZ/2);
|
||||
pop_ctrl(1);
|
||||
sleep(HZ/4);
|
||||
audiohw_unmute();
|
||||
}
|
||||
|
||||
void audiohw_close(void)
|
||||
{
|
||||
audiohw_mute();
|
||||
pop_ctrl(0);
|
||||
sleep(HZ/4);
|
||||
}
|
||||
99
firmware/target/arm/rk27xx/ihifi2/button-ihifi.c
Normal file
99
firmware/target/arm/rk27xx/ihifi2/button-ihifi.c
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "kernel.h"
|
||||
#include "button.h"
|
||||
#include "adc.h"
|
||||
#include "backlight.h"
|
||||
|
||||
static bool soft_hold = false;
|
||||
#ifndef BOOTLOADER
|
||||
static unsigned hold_counter = 0;
|
||||
#ifndef IHIFI800
|
||||
#define HOLDBUTTON gpio_btn
|
||||
#define HOLDCNTMAX HZ
|
||||
#else
|
||||
#define HOLDBUTTON (gpio_btn) && (adc_val > 325) && (adc_val < 480)
|
||||
#define HOLDCNTMAX (HZ/10)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void button_init_device(void) {
|
||||
GPIO_PCCON &= ~(1<<1); /* PWR BTN */
|
||||
GPIO_PCCON &= ~(1<<7); /* CD */
|
||||
}
|
||||
|
||||
bool button_hold(void)
|
||||
{
|
||||
return soft_hold;
|
||||
}
|
||||
|
||||
int button_read_device(void) {
|
||||
int adc_val = adc_read(ADC_BUTTONS);
|
||||
int gpio_btn = GPIO_PCDR & (1<<1);
|
||||
|
||||
int button = BUTTON_NONE;
|
||||
|
||||
if (gpio_btn)
|
||||
button |= BUTTON_POWER;
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
if (HOLDBUTTON) {
|
||||
if (++hold_counter == HOLDCNTMAX) {
|
||||
soft_hold = !soft_hold;
|
||||
backlight_hold_changed(soft_hold);
|
||||
}
|
||||
} else {
|
||||
hold_counter = 0;
|
||||
}
|
||||
if (soft_hold) {
|
||||
return (hold_counter <= HOLDCNTMAX) ? BUTTON_NONE : button;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (adc_val < 792) {
|
||||
if (adc_val < 480) {
|
||||
if (adc_val < 170) {
|
||||
if (adc_val < 46) {
|
||||
button |= BUTTON_HOME; // 0-45
|
||||
} else {
|
||||
button |= BUTTON_PLAY; // 46-169
|
||||
}
|
||||
} else {
|
||||
if (adc_val < 325) {
|
||||
button |= BUTTON_NEXT; // 170-324
|
||||
} else {
|
||||
button |= BUTTON_VOL_UP;// 325-479
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (adc_val < 636) {
|
||||
button |= BUTTON_VOL_DOWN;// 480-635
|
||||
} else {
|
||||
button |= BUTTON_PREV; // 636-791
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return button;
|
||||
}
|
||||
50
firmware/target/arm/rk27xx/ihifi2/button-target.h
Normal file
50
firmware/target/arm/rk27xx/ihifi2/button-target.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef _BUTTON_TARGET_H_
|
||||
#define _BUTTON_TARGET_H_
|
||||
|
||||
#define HAS_BUTTON_HOLD
|
||||
|
||||
/* Main unit's buttons */
|
||||
#define BUTTON_POWER 0x00000001
|
||||
#define BUTTON_HOME 0x00000002
|
||||
#define BUTTON_PREV 0x00000004
|
||||
#define BUTTON_NEXT 0x00000008
|
||||
#define BUTTON_PLAY 0x00000010
|
||||
#define BUTTON_VOL_UP 0x00000020
|
||||
#define BUTTON_VOL_DOWN 0x00000040
|
||||
|
||||
#define BUTTON_LEFT 0
|
||||
#define BUTTON_RIGHT 0
|
||||
|
||||
#define BUTTON_MAIN (BUTTON_POWER | BUTTON_HOME | BUTTON_PREV | BUTTON_NEXT | \
|
||||
BUTTON_PLAY | BUTTON_VOL_UP | BUTTON_VOL_DOWN)
|
||||
|
||||
/* Software power-off */
|
||||
#ifndef IHIFI800
|
||||
#define POWEROFF_BUTTON BUTTON_POWER
|
||||
#else
|
||||
#define POWEROFF_BUTTON BUTTON_HOME
|
||||
#endif
|
||||
|
||||
#define POWEROFF_COUNT 30
|
||||
|
||||
#endif /* _BUTTON_TARGET_H_ */
|
||||
285
firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c
Normal file
285
firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
#include "lcd.h"
|
||||
#include "system.h"
|
||||
#include "cpu.h"
|
||||
#include "lcdif-rk27xx.h"
|
||||
|
||||
static bool display_on = false;
|
||||
|
||||
void lcd_display_init(void)
|
||||
{
|
||||
unsigned int i, x, y;
|
||||
|
||||
lcd_cmd(0x11);
|
||||
|
||||
lcd_cmd(0x13);
|
||||
|
||||
mdelay(120);
|
||||
|
||||
lcd_cmd(0x29);
|
||||
|
||||
lcd_cmd(0xB0);
|
||||
lcd_data(0x05);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0xF0);
|
||||
lcd_data(0x0A);
|
||||
lcd_data(0x41);
|
||||
lcd_data(0x02);
|
||||
lcd_data(0x0A);
|
||||
lcd_data(0x30);
|
||||
lcd_data(0x31);
|
||||
lcd_data(0x36);
|
||||
lcd_data(0x37);
|
||||
lcd_data(0x40);
|
||||
lcd_data(0x02);
|
||||
lcd_data(0x3F);
|
||||
lcd_data(0x40);
|
||||
lcd_data(0x02);
|
||||
lcd_data(0x81);
|
||||
lcd_data(0x04);
|
||||
lcd_data(0x05);
|
||||
lcd_data(0x64);
|
||||
|
||||
lcd_cmd(0xFC);
|
||||
lcd_data(0x88);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x42);
|
||||
lcd_data(0x42);
|
||||
lcd_data(0x22);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x22);
|
||||
lcd_data(0x99);
|
||||
lcd_data(0xAA);
|
||||
lcd_data(0xAA);
|
||||
lcd_data(0xAA);
|
||||
lcd_data(0xBB);
|
||||
lcd_data(0xBB);
|
||||
lcd_data(0xAA);
|
||||
lcd_data(0x33);
|
||||
lcd_data(0x33);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0xC0);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0xFD);
|
||||
lcd_data(0x88);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x42);
|
||||
lcd_data(0x42);
|
||||
lcd_data(0x22);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x22);
|
||||
lcd_data(0x99);
|
||||
lcd_data(0xAA);
|
||||
lcd_data(0xAA);
|
||||
lcd_data(0xAA);
|
||||
lcd_data(0xBB);
|
||||
lcd_data(0xBB);
|
||||
lcd_data(0xAA);
|
||||
lcd_data(0x33);
|
||||
lcd_data(0x33);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x03);
|
||||
|
||||
lcd_cmd(0xBE);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x15);
|
||||
lcd_data(0x16);
|
||||
lcd_data(0x08);
|
||||
lcd_data(0x09);
|
||||
lcd_data(0x15);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0xC0);
|
||||
lcd_data(0x0E);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0xC1);
|
||||
lcd_data(0x2F);
|
||||
lcd_data(0x23);
|
||||
lcd_data(0xB4);
|
||||
lcd_data(0xFF);
|
||||
lcd_data(0x24);
|
||||
lcd_data(0x03);
|
||||
lcd_data(0x20);
|
||||
lcd_data(0x02);
|
||||
lcd_data(0x02);
|
||||
lcd_data(0x02);
|
||||
lcd_data(0x20);
|
||||
lcd_data(0x20);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0xC2);
|
||||
lcd_data(0x03);
|
||||
|
||||
lcd_cmd(0x26);
|
||||
lcd_data(0x08);
|
||||
|
||||
lcd_cmd(0x35);
|
||||
|
||||
lcd_cmd(0x36);
|
||||
lcd_data(0x04);
|
||||
|
||||
lcd_cmd(0x3A);
|
||||
lcd_data(0x05);
|
||||
|
||||
lcd_cmd(0x2A);
|
||||
lcd_data(0x013F);
|
||||
|
||||
lcd_cmd(0x2B);
|
||||
lcd_data(0xEF);
|
||||
|
||||
lcd_cmd(0x2C);
|
||||
|
||||
lcd_cmd(0x2D);
|
||||
for (i = 0; i < 0x20; i++) {
|
||||
lcd_data(i << 1);
|
||||
}
|
||||
for (i = 0; i < 0x40; i++) {
|
||||
lcd_data(i);
|
||||
}
|
||||
for (i = 0; i < 0x20; i++) {
|
||||
lcd_data(i << 1);
|
||||
}
|
||||
|
||||
lcd_cmd(0x2A);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0x2B);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0x11);
|
||||
|
||||
mdelay(120);
|
||||
|
||||
lcd_cmd(0x29);
|
||||
|
||||
lcd_cmd(0x2C);
|
||||
|
||||
for (x = 0; x < LCD_WIDTH; x++)
|
||||
for(y=0; y < LCD_HEIGHT; y++)
|
||||
lcd_data(0x00);
|
||||
|
||||
display_on = true;
|
||||
}
|
||||
|
||||
void lcd_enable (bool on)
|
||||
{
|
||||
if (on == display_on)
|
||||
return;
|
||||
|
||||
lcdctrl_bypass(1);
|
||||
LCDC_CTRL |= RGB24B;
|
||||
|
||||
if (on) {
|
||||
lcd_cmd(0x11);
|
||||
mdelay(120);
|
||||
lcd_cmd(0x29);
|
||||
lcd_cmd(0x2C);
|
||||
} else {
|
||||
lcd_cmd(0x28);
|
||||
mdelay(120);
|
||||
lcd_cmd(0x10);
|
||||
}
|
||||
|
||||
display_on = on;
|
||||
LCDC_CTRL &= ~RGB24B;
|
||||
}
|
||||
|
||||
void lcd_set_gram_area(int x_start, int y_start,
|
||||
int x_end, int y_end)
|
||||
{
|
||||
lcdctrl_bypass(1);
|
||||
LCDC_CTRL |= RGB24B;
|
||||
|
||||
lcd_cmd(0x2A);
|
||||
lcd_data((x_start&0xff00)>>8);
|
||||
lcd_data(x_start&0x00ff);
|
||||
lcd_data((x_end&0xff00)>>8);
|
||||
lcd_data(x_end&0x00ff);
|
||||
|
||||
lcd_cmd(0x2B);
|
||||
lcd_data((y_start&0xff00)>>8);
|
||||
lcd_data(y_start&0x00ff);
|
||||
lcd_data((y_end&0xff00)>>8);
|
||||
lcd_data(y_end&0x00ff);
|
||||
|
||||
lcd_cmd(0x2C);
|
||||
|
||||
LCDC_CTRL &= ~RGB24B;
|
||||
}
|
||||
|
||||
bool lcd_active()
|
||||
{
|
||||
return display_on;
|
||||
}
|
||||
|
||||
/* Blit a YUV bitmap directly to the LCD */
|
||||
void lcd_blit_yuv(unsigned char * const src[3],
|
||||
int src_x, int src_y, int stride,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
(void)src;
|
||||
(void)src_x;
|
||||
(void)src_y;
|
||||
(void)stride;
|
||||
(void)x;
|
||||
(void)y;
|
||||
(void)width;
|
||||
(void)height;
|
||||
}
|
||||
248
firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c
Normal file
248
firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
#include "lcd.h"
|
||||
#include "system.h"
|
||||
#include "cpu.h"
|
||||
#include "lcdif-rk27xx.h"
|
||||
|
||||
static bool display_on = false;
|
||||
|
||||
void lcd_display_init(void)
|
||||
{
|
||||
unsigned int x, y;
|
||||
|
||||
lcd_cmd(0x13);
|
||||
|
||||
mdelay(120);
|
||||
|
||||
lcd_cmd(0x35);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0x36);
|
||||
lcd_data(0x48);
|
||||
|
||||
lcd_cmd(0xD0);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x05);
|
||||
|
||||
lcd_cmd(0xEF);
|
||||
lcd_data(0x07);
|
||||
|
||||
lcd_cmd(0xF2);
|
||||
lcd_data(0x1B);
|
||||
lcd_data(0x16);
|
||||
lcd_data(0x0F);
|
||||
lcd_data(0x08);
|
||||
lcd_data(0x08);
|
||||
lcd_data(0x08);
|
||||
lcd_data(0x08);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x1C);
|
||||
lcd_data(0x16);
|
||||
|
||||
lcd_cmd(0xF3);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x41);
|
||||
lcd_data(0x15);
|
||||
lcd_data(0x0D);
|
||||
lcd_data(0x33);
|
||||
lcd_data(0x63);
|
||||
lcd_data(0x46);
|
||||
lcd_data(0x10);
|
||||
|
||||
lcd_cmd(0xF4);
|
||||
lcd_data(0x5B);
|
||||
lcd_data(0x5B);
|
||||
lcd_data(0x55);
|
||||
lcd_data(0x55);
|
||||
lcd_data(0x44);
|
||||
|
||||
lcd_cmd(0xF5);
|
||||
lcd_data(0x12);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x06);
|
||||
lcd_data(0xF0);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x1F);
|
||||
|
||||
lcd_cmd(0xF6);
|
||||
lcd_data(0x80);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0xFD);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x1D);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0xF8);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x15);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x08);
|
||||
lcd_data(0x15);
|
||||
lcd_data(0x22);
|
||||
lcd_data(0x25);
|
||||
lcd_data(0x28);
|
||||
lcd_data(0x14);
|
||||
lcd_data(0x13);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x09);
|
||||
lcd_data(0x24);
|
||||
lcd_data(0x28);
|
||||
|
||||
lcd_cmd(0xF9);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x15);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x08);
|
||||
lcd_data(0x15);
|
||||
lcd_data(0x22);
|
||||
lcd_data(0x25);
|
||||
lcd_data(0x28);
|
||||
lcd_data(0x14);
|
||||
lcd_data(0x13);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x09);
|
||||
lcd_data(0x24);
|
||||
lcd_data(0x28);
|
||||
|
||||
lcd_cmd(0xFC);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x15);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x08);
|
||||
lcd_data(0x15);
|
||||
lcd_data(0x22);
|
||||
lcd_data(0x25);
|
||||
lcd_data(0x28);
|
||||
lcd_data(0x14);
|
||||
lcd_data(0x13);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x09);
|
||||
lcd_data(0x24);
|
||||
lcd_data(0x28);
|
||||
|
||||
lcd_cmd(0x36);
|
||||
lcd_data(0x48);
|
||||
|
||||
lcd_cmd(0x3A);
|
||||
lcd_data(0x55);
|
||||
|
||||
lcd_cmd(0x2A);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x3F);
|
||||
|
||||
lcd_cmd(0x2B);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0xEF);
|
||||
|
||||
lcd_cmd(0x11);
|
||||
|
||||
mdelay(120);
|
||||
|
||||
lcd_cmd(0x29);
|
||||
|
||||
lcd_cmd(0x2C);
|
||||
|
||||
for (x = 0; x < LCD_WIDTH; x++)
|
||||
for(y=0; y < LCD_HEIGHT; y++)
|
||||
lcd_data(0x00);
|
||||
|
||||
display_on = true;
|
||||
}
|
||||
|
||||
void lcd_enable (bool on)
|
||||
{
|
||||
if (on == display_on)
|
||||
return;
|
||||
|
||||
lcdctrl_bypass(1);
|
||||
LCDC_CTRL |= RGB24B;
|
||||
|
||||
if (on) {
|
||||
lcd_cmd(0x11);
|
||||
mdelay(120);
|
||||
lcd_cmd(0x29);
|
||||
lcd_cmd(0x2C);
|
||||
} else {
|
||||
lcd_cmd(0x28);
|
||||
mdelay(120);
|
||||
lcd_cmd(0x10);
|
||||
}
|
||||
|
||||
display_on = on;
|
||||
LCDC_CTRL &= ~RGB24B;
|
||||
}
|
||||
|
||||
void lcd_set_gram_area(int x_start, int y_start,
|
||||
int x_end, int y_end)
|
||||
{
|
||||
lcdctrl_bypass(1);
|
||||
LCDC_CTRL |= RGB24B;
|
||||
|
||||
lcd_cmd(0x2A);
|
||||
lcd_data((x_start&0xff00)>>8);
|
||||
lcd_data(x_start&0x00ff);
|
||||
lcd_data((x_end&0xff00)>>8);
|
||||
lcd_data(x_end&0x00ff);
|
||||
|
||||
lcd_cmd(0x2B);
|
||||
lcd_data((y_start&0xff00)>>8);
|
||||
lcd_data(y_start&0x00ff);
|
||||
lcd_data((y_end&0xff00)>>8);
|
||||
lcd_data(y_end&0x00ff);
|
||||
|
||||
lcd_cmd(0x2C);
|
||||
|
||||
LCDC_CTRL &= ~RGB24B;
|
||||
}
|
||||
|
||||
bool lcd_active()
|
||||
{
|
||||
return display_on;
|
||||
}
|
||||
|
||||
/* Blit a YUV bitmap directly to the LCD */
|
||||
void lcd_blit_yuv(unsigned char * const src[3],
|
||||
int src_x, int src_y, int stride,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
(void)src;
|
||||
(void)src_x;
|
||||
(void)src_y;
|
||||
(void)stride;
|
||||
(void)x;
|
||||
(void)y;
|
||||
(void)width;
|
||||
(void)height;
|
||||
}
|
||||
228
firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c
Normal file
228
firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
#include "lcd.h"
|
||||
#include "system.h"
|
||||
#include "cpu.h"
|
||||
#include "lcdif-rk27xx.h"
|
||||
|
||||
static bool display_on = false;
|
||||
|
||||
void lcd_display_init(void)
|
||||
{
|
||||
unsigned int x, y;
|
||||
|
||||
lcd_cmd(0xEF);
|
||||
lcd_data(0x03);
|
||||
lcd_data(0x80);
|
||||
lcd_data(0x02);
|
||||
|
||||
lcd_cmd(0xCF);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0xC1);
|
||||
lcd_data(0x30);
|
||||
|
||||
lcd_cmd(0xED);
|
||||
lcd_data(0x67);
|
||||
lcd_data(0x03);
|
||||
lcd_data(0x12);
|
||||
lcd_data(0x81);
|
||||
|
||||
lcd_cmd(0xE8);
|
||||
lcd_data(0x85);
|
||||
lcd_data(0x11);
|
||||
lcd_data(0x79);
|
||||
|
||||
lcd_cmd(0xCB);
|
||||
lcd_data(0x39);
|
||||
lcd_data(0x2C);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x34);
|
||||
lcd_data(0x06);
|
||||
|
||||
lcd_cmd(0xF7);
|
||||
lcd_data(0x20);
|
||||
|
||||
lcd_cmd(0xEA);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0xC0);
|
||||
lcd_data(0x1D);
|
||||
|
||||
lcd_cmd(0xC1);
|
||||
lcd_data(0x12);
|
||||
|
||||
lcd_cmd(0xC5);
|
||||
lcd_data(0x44);
|
||||
lcd_data(0x3C);
|
||||
|
||||
lcd_cmd(0xC7);
|
||||
lcd_data(0x88);
|
||||
|
||||
lcd_cmd(0x3A);
|
||||
lcd_data(0x55);
|
||||
|
||||
lcd_cmd(0x36);
|
||||
lcd_data(0x0C);
|
||||
|
||||
lcd_cmd(0xB1);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x17);
|
||||
|
||||
lcd_cmd(0xB6);
|
||||
lcd_data(0x0A);
|
||||
lcd_data(0xA2);
|
||||
|
||||
lcd_cmd(0xF2);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0x26);
|
||||
lcd_data(0x01);
|
||||
|
||||
lcd_cmd(0xE0);
|
||||
lcd_data(0x0F);
|
||||
lcd_data(0x22);
|
||||
lcd_data(0x1C);
|
||||
lcd_data(0x1B);
|
||||
lcd_data(0x08);
|
||||
lcd_data(0x0F);
|
||||
lcd_data(0x48);
|
||||
lcd_data(0xB8);
|
||||
lcd_data(0x34);
|
||||
lcd_data(0x05);
|
||||
lcd_data(0x0C);
|
||||
lcd_data(0x09);
|
||||
lcd_data(0x0F);
|
||||
lcd_data(0x07);
|
||||
lcd_data(0x00);
|
||||
|
||||
lcd_cmd(0xE1);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x23);
|
||||
lcd_data(0x24);
|
||||
lcd_data(0x07);
|
||||
lcd_data(0x10);
|
||||
lcd_data(0x07);
|
||||
lcd_data(0x38);
|
||||
lcd_data(0x47);
|
||||
lcd_data(0x4B);
|
||||
lcd_data(0x0A);
|
||||
lcd_data(0x13);
|
||||
lcd_data(0x06);
|
||||
lcd_data(0x30);
|
||||
lcd_data(0x38);
|
||||
lcd_data(0x0F);
|
||||
|
||||
lcd_cmd(0x2A);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0xEF);
|
||||
|
||||
lcd_cmd(0x2B);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x00);
|
||||
lcd_data(0x01);
|
||||
lcd_data(0x3F);
|
||||
|
||||
lcd_cmd(0x11);
|
||||
|
||||
mdelay(120);
|
||||
|
||||
lcd_cmd(0x29);
|
||||
|
||||
lcd_cmd(0x2C);
|
||||
|
||||
for (x = 0; x < LCD_WIDTH; x++)
|
||||
for(y=0; y < LCD_HEIGHT; y++)
|
||||
lcd_data(0x00);
|
||||
|
||||
display_on = true;
|
||||
}
|
||||
|
||||
void lcd_enable (bool on)
|
||||
{
|
||||
if (on == display_on)
|
||||
return;
|
||||
|
||||
lcdctrl_bypass(1);
|
||||
LCDC_CTRL |= RGB24B;
|
||||
|
||||
if (on) {
|
||||
lcd_cmd(0x11);
|
||||
mdelay(120);
|
||||
lcd_cmd(0x29);
|
||||
lcd_cmd(0x2C);
|
||||
} else {
|
||||
lcd_cmd(0x28);
|
||||
mdelay(120);
|
||||
lcd_cmd(0x10);
|
||||
}
|
||||
|
||||
display_on = on;
|
||||
LCDC_CTRL &= ~RGB24B;
|
||||
}
|
||||
|
||||
void lcd_set_gram_area(int x_start, int y_start,
|
||||
int x_end, int y_end)
|
||||
{
|
||||
lcdctrl_bypass(1);
|
||||
LCDC_CTRL |= RGB24B;
|
||||
|
||||
lcd_cmd(0x2A);
|
||||
lcd_data((x_start&0xff00)>>8);
|
||||
lcd_data(x_start&0x00ff);
|
||||
lcd_data((x_end&0xff00)>>8);
|
||||
lcd_data(x_end&0x00ff);
|
||||
|
||||
lcd_cmd(0x2B);
|
||||
lcd_data((y_start&0xff00)>>8);
|
||||
lcd_data(y_start&0x00ff);
|
||||
lcd_data((y_end&0xff00)>>8);
|
||||
lcd_data(y_end&0x00ff);
|
||||
|
||||
lcd_cmd(0x2C);
|
||||
|
||||
LCDC_CTRL &= ~RGB24B;
|
||||
}
|
||||
|
||||
bool lcd_active()
|
||||
{
|
||||
return display_on;
|
||||
}
|
||||
|
||||
/* Blit a YUV bitmap directly to the LCD */
|
||||
void lcd_blit_yuv(unsigned char * const src[3],
|
||||
int src_x, int src_y, int stride,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
(void)src;
|
||||
(void)src_x;
|
||||
(void)src_y;
|
||||
(void)stride;
|
||||
(void)x;
|
||||
(void)y;
|
||||
(void)width;
|
||||
(void)height;
|
||||
}
|
||||
26
firmware/target/arm/rk27xx/ihifi2/lcd-target.h
Normal file
26
firmware/target/arm/rk27xx/ihifi2/lcd-target.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef LCD_TARGET_H
|
||||
#define LCD_TARGET_H
|
||||
|
||||
#define LCD_DATABUS_WIDTH LCDIF_16BIT
|
||||
#endif
|
||||
53
firmware/target/arm/rk27xx/ihifi2/power-ihifi.c
Normal file
53
firmware/target/arm/rk27xx/ihifi2/power-ihifi.c
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdbool.h>
|
||||
#include "config.h"
|
||||
#include "inttypes.h"
|
||||
#include "power.h"
|
||||
#include "panic.h"
|
||||
#include "system.h"
|
||||
#include "usb_core.h" /* for usb_charging_maxcurrent_change */
|
||||
#include "adc.h"
|
||||
|
||||
void power_off(void)
|
||||
{
|
||||
GPIO_PCCON &= ~(1<<0);
|
||||
while(1);
|
||||
}
|
||||
|
||||
void power_init(void)
|
||||
{
|
||||
GPIO_PCDR |= (1<<0);
|
||||
GPIO_PCCON |= (1<<0);
|
||||
|
||||
GPIO_PADR &= ~(1<<7); /* MUTE */
|
||||
GPIO_PACON |= (1<<7);
|
||||
}
|
||||
|
||||
unsigned int power_input_status(void)
|
||||
{
|
||||
return (usb_detect() == USB_INSERTED) ? POWER_INPUT_MAIN_CHARGER : POWER_INPUT_NONE;
|
||||
}
|
||||
|
||||
bool charging_state(void)
|
||||
{
|
||||
return (adc_read(ADC_EXTRA) < 512);
|
||||
}
|
||||
64
firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770.c
Normal file
64
firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "adc.h"
|
||||
#include "adc-target.h"
|
||||
#include "powermgmt.h"
|
||||
|
||||
/* Battery voltage calculation and discharge/charge curves for the iHiFi 770
|
||||
|
||||
Battery voltage is calculated under the assumption that the adc full-scale
|
||||
readout represents 3.00V and that the battery ADC channel is fed with
|
||||
exactly half of the battery voltage (through a resistive divider).
|
||||
Charge curve have not been calibrated yet.
|
||||
*/
|
||||
|
||||
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
/* 5% */
|
||||
3500,
|
||||
};
|
||||
|
||||
const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
/* 0% */
|
||||
3300,
|
||||
};
|
||||
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
|
||||
const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
|
||||
{
|
||||
{ 3300, 3570, 3660, 3696, 3712, 3742, 3798, 3865, 3935, 4020, 4130 }
|
||||
};
|
||||
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
|
||||
const unsigned short percent_to_volt_charge[11] =
|
||||
{ 3300, 3570, 3660, 3696, 3712, 3742, 3798, 3865, 3935, 4020, 4130 };
|
||||
|
||||
/* full-scale ADC readout (2^10) in millivolt */
|
||||
#define BATTERY_SCALE_FACTOR 6296
|
||||
|
||||
/* Returns battery voltage from ADC [millivolts] */
|
||||
int _battery_voltage(void)
|
||||
{
|
||||
return (adc_read(ADC_BATTERY) * BATTERY_SCALE_FACTOR) >> 10;
|
||||
}
|
||||
64
firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770c.c
Normal file
64
firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi770c.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "adc.h"
|
||||
#include "adc-target.h"
|
||||
#include "powermgmt.h"
|
||||
|
||||
/* Battery voltage calculation and discharge/charge curves for the iHiFi 770C
|
||||
|
||||
Battery voltage is calculated under the assumption that the adc full-scale
|
||||
readout represents 3.00V and that the battery ADC channel is fed with
|
||||
exactly half of the battery voltage (through a resistive divider).
|
||||
Charge curve have not been calibrated yet.
|
||||
*/
|
||||
|
||||
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
/* 5% */
|
||||
3500,
|
||||
};
|
||||
|
||||
const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
/* 0% */
|
||||
3300,
|
||||
};
|
||||
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
|
||||
const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
|
||||
{
|
||||
{ 3300, 3570, 3660, 3696, 3712, 3742, 3798, 3865, 3935, 4020, 4130 }
|
||||
};
|
||||
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
|
||||
const unsigned short percent_to_volt_charge[11] =
|
||||
{ 3300, 3570, 3660, 3696, 3712, 3742, 3798, 3865, 3935, 4020, 4130 };
|
||||
|
||||
/* full-scale ADC readout (2^10) in millivolt */
|
||||
#define BATTERY_SCALE_FACTOR 6296
|
||||
|
||||
/* Returns battery voltage from ADC [millivolts] */
|
||||
int _battery_voltage(void)
|
||||
{
|
||||
return (adc_read(ADC_BATTERY) * BATTERY_SCALE_FACTOR) >> 10;
|
||||
}
|
||||
64
firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi800.c
Normal file
64
firmware/target/arm/rk27xx/ihifi2/powermgmt-ihifi800.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 by Roman Stolyarov
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "adc.h"
|
||||
#include "adc-target.h"
|
||||
#include "powermgmt.h"
|
||||
|
||||
/* Battery voltage calculation and discharge/charge curves for the iHiFi 800
|
||||
|
||||
Battery voltage is calculated under the assumption that the adc full-scale
|
||||
readout represents 3.00V and that the battery ADC channel is fed with
|
||||
exactly half of the battery voltage (through a resistive divider).
|
||||
Charge curve have not been calibrated yet.
|
||||
*/
|
||||
|
||||
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
/* 5% */
|
||||
3628,
|
||||
};
|
||||
|
||||
const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
|
||||
{
|
||||
/* 0% */
|
||||
3300,
|
||||
};
|
||||
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
|
||||
const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
|
||||
{
|
||||
{ 3300, 3649, 3701, 3726, 3745, 3778, 3831, 3904, 3965, 4056, 4160 }
|
||||
};
|
||||
|
||||
/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
|
||||
const unsigned short percent_to_volt_charge[11] =
|
||||
{ 3300, 3649, 3701, 3726, 3745, 3778, 3831, 3904, 3965, 4056, 4160 };
|
||||
|
||||
/* full-scale ADC readout (2^10) in millivolt */
|
||||
#define BATTERY_SCALE_FACTOR 6296
|
||||
|
||||
/* Returns battery voltage from ADC [millivolts] */
|
||||
int _battery_voltage(void)
|
||||
{
|
||||
return (adc_read(ADC_BATTERY) * BATTERY_SCALE_FACTOR) >> 10;
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ void INT_SD(void)
|
|||
/* get the status */
|
||||
cmd_error = SD_CMDRES;
|
||||
semaphore_release(&command_completion_signal);
|
||||
}
|
||||
}
|
||||
|
||||
/* data transfer status pending */
|
||||
if(status & DATA_XFER_STAT)
|
||||
|
|
@ -140,13 +140,15 @@ static void mmu_buff_reset(void)
|
|||
|
||||
static inline bool card_detect_target(void)
|
||||
{
|
||||
#if defined(RK27_GENERIC)
|
||||
/* My generic device uses PC7 pin, active low */
|
||||
#if defined(RK27_GENERIC) || defined(IHIFI770) || defined(IHIFI770C) || defined(IHIFI800)
|
||||
/* PC7, active low */
|
||||
return !(GPIO_PCDR & 0x80);
|
||||
#elif defined(HM60X) || defined(HM801)
|
||||
/* PF2, active low */
|
||||
return !(GPIO_PFDR & (1<<2));
|
||||
#elif defined(MA9) || defined(MA9C) || defined(MA8) || defined(MA8C)
|
||||
return (GPIO_PCDR & 0x80);
|
||||
/* PC7, active high */
|
||||
return (GPIO_PCDR & (1<<7));
|
||||
#elif defined(IHIFI760) || defined(IHIFI960)
|
||||
/* TODO: find out pin */
|
||||
return true;
|
||||
|
|
@ -190,7 +192,7 @@ static bool send_cmd(const int cmd, const int arg, const int res,
|
|||
#if 0
|
||||
/* for some misterious reason the card does not report itself as being in TRAN
|
||||
* but transfers are successful. Rockchip OF does not check the card state
|
||||
* after SELECT. I checked two different cards.
|
||||
* after SELECT. I checked two different cards.
|
||||
*/
|
||||
static void print_card_status(void)
|
||||
{
|
||||
|
|
@ -224,7 +226,7 @@ static int sd_wait_for_tran_state(void)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if(TIME_AFTER(current_tick, timeout))
|
||||
{
|
||||
return -10 * ((response >> 9) & 0xf);
|
||||
|
|
@ -265,7 +267,7 @@ static int sd_init_card(void)
|
|||
/* CMD0 Go Idle */
|
||||
if(!send_cmd(SD_GO_IDLE_STATE, 0, RES_NO, NULL))
|
||||
return -1;
|
||||
|
||||
|
||||
sleep(1);
|
||||
|
||||
/* CMD8 Check for v2 sd card. Must be sent before using ACMD41
|
||||
|
|
@ -671,7 +673,7 @@ int sd_write_sectors(IF_MD(int drive,) unsigned long start, int count,
|
|||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||
|
||||
#endif /* defined(BOOTLOADER) */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,37 +28,16 @@
|
|||
#include "kernel.h"
|
||||
#include "panic.h"
|
||||
|
||||
//#include "usb-s3c6400x.h"
|
||||
|
||||
#include "usb_ch9.h"
|
||||
#include "usb_core.h"
|
||||
#include <inttypes.h>
|
||||
#include "power.h"
|
||||
|
||||
#define LOGF_ENABLE
|
||||
#include "logf.h"
|
||||
|
||||
typedef volatile uint32_t reg32;
|
||||
|
||||
/* Bulk OUT: ep1, ep4, ep7, ep10, ep13 */
|
||||
#define BOUT_RXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x54+0x38*(ep_num/3)))
|
||||
#define BOUT_RXCON(ep_num) (*(reg32*)(AHB0_UDC+0x58+0x38*(ep_num/3)))
|
||||
#define BOUT_DMAOUTCTL(ep_num) (*(reg32*)(AHB0_UDC+0x5C+0x38*(ep_num/3)))
|
||||
#define BOUT_DMAOUTLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x60+0x38*(ep_num/3)))
|
||||
|
||||
/* Bulk IN: ep2, ep5, ep8, ep11, ep4 */
|
||||
#define BIN_TXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x64+0x38*(ep_num/3)))
|
||||
#define BIN_TXCON(ep_num) (*(reg32*)(AHB0_UDC+0x68+0x38*(ep_num/3)))
|
||||
#define BIN_TXBUF(ep_num) (*(reg32*)(AHB0_UDC+0x6C+0x38*(ep_num/3)))
|
||||
#define BIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x70+0x38*(ep_num/3)))
|
||||
#define BIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x74+0x38*(ep_num/3)))
|
||||
|
||||
/* INTERRUPT IN: ep3, ep6, ep9, ep12, ep15 */
|
||||
#define IIN_TXSTAT(ep_num) (*(reg32*)(AHB0_UDC+0x78+0x38*((ep_num/3)-1)))
|
||||
#define IIN_TXCON(ep_num) (*(reg32*)(AHB0_UDC+0x7C+0x38*((ep_num/3)-1)))
|
||||
#define IIN_TXBUF(ep_num) (*(reg32*)(AHB0_UDC+0x80+0x38*((ep_num/3)-1)))
|
||||
#define IIN_DMAINCTL(ep_num) (*(reg32*)(AHB0_UDC+0x84+0x38*((ep_num/3)-1)))
|
||||
#define IIN_DMAINLMADDR(ep_num) (*(reg32*)(AHB0_UDC+0x88+0x38*((ep_num/3)-1)))
|
||||
|
||||
#ifdef LOGF_ENABLE
|
||||
#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT")
|
||||
#define XFER_TYPE_STR(type) \
|
||||
|
|
@ -68,9 +47,12 @@ typedef volatile uint32_t reg32;
|
|||
((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL"))))
|
||||
#endif
|
||||
|
||||
struct endpoint_t {
|
||||
struct endpoint_t
|
||||
{
|
||||
const int ep_num; /* EP number */
|
||||
const int type; /* EP type */
|
||||
const int dir; /* DIR_IN/DIR_OUT */
|
||||
volatile unsigned long *stat; /* RXSTAT/TXSTAT register */
|
||||
bool allocated; /* flag to mark EPs taken */
|
||||
volatile void *buf; /* tx/rx buffer address */
|
||||
volatile int len; /* size of the transfer (bytes) */
|
||||
|
|
@ -79,67 +61,91 @@ struct endpoint_t {
|
|||
struct semaphore complete; /* semaphore for blocking transfers */
|
||||
};
|
||||
|
||||
#define EP_INIT(_type, _dir, _alloced, _buf, _len, _cnt, _block) \
|
||||
{ .type = (_type), .dir = (_dir), .allocated = (_alloced), .buf = (_buf), \
|
||||
.len = (_len), .cnt = (_cnt), .block = (_block) }
|
||||
/* compute RXCON address from RXSTAT, and so on */
|
||||
#define RXSTAT(endp) *((endp)->stat)
|
||||
#define RXCON(endp) *(1 + (endp)->stat)
|
||||
#define DMAOUTCTL(endp) *(2 + (endp)->stat)
|
||||
#define DMAOUTLMADDR(endp) *(3 + (endp)->stat)
|
||||
/* compute TXCON address from TXSTAT, and so on */
|
||||
#define TXSTAT(endp) *((endp)->stat)
|
||||
#define TXCON(endp) *(1 + (endp)->stat)
|
||||
#define TXBUF(endp) *(2 + (endp)->stat)
|
||||
#define DMAINCTL(endp) *(3 + (endp)->stat)
|
||||
#define DMAINLMADDR(endp) *(4 + (endp)->stat)
|
||||
|
||||
static struct endpoint_t ctrlep[2] = {
|
||||
EP_INIT(USB_ENDPOINT_XFER_CONTROL, DIR_OUT, true, NULL, 0, 0, true),
|
||||
EP_INIT(USB_ENDPOINT_XFER_CONTROL, DIR_IN, true, NULL, 0, 0, true),
|
||||
#define ENDPOINT(num, type, dir, reg) \
|
||||
{num, USB_ENDPOINT_XFER_##type, USB_DIR_##dir, reg, false, NULL, 0, 0, true, {{0, 0}, 0, 0}}
|
||||
|
||||
static struct endpoint_t ctrlep[2] =
|
||||
{
|
||||
ENDPOINT(0, CONTROL, OUT, &RX0STAT),
|
||||
ENDPOINT(0, CONTROL, IN, &TX0STAT),
|
||||
};
|
||||
|
||||
static struct endpoint_t endpoints[16] = {
|
||||
EP_INIT(USB_ENDPOINT_XFER_CONTROL, 3, true, NULL, 0, 0, true ), /* stub */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT1 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN2 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN3 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT4 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN5 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN6 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT7 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN8 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN9 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT10 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN11 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN12 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_OUT, false, NULL, 0, 0, false ), /* BOUT13 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_BULK, DIR_IN, false, NULL, 0, 0, false ), /* BIN14 */
|
||||
EP_INIT(USB_ENDPOINT_XFER_INT, DIR_IN, false, NULL, 0, 0, false ), /* IIN15 */
|
||||
static struct endpoint_t endpoints[16] =
|
||||
{
|
||||
ENDPOINT(0, CONTROL, OUT, NULL), /* stub */
|
||||
ENDPOINT(1, BULK, OUT, &RX1STAT), /* BOUT1 */
|
||||
ENDPOINT(2, BULK, IN, &TX2STAT), /* BIN2 */
|
||||
ENDPOINT(3, INT, IN, &TX3STAT), /* IIN3 */
|
||||
ENDPOINT(4, BULK, OUT, &RX4STAT), /* BOUT4 */
|
||||
ENDPOINT(5, BULK, IN, &TX5STAT), /* BIN5 */
|
||||
ENDPOINT(6, INT, IN, &TX6STAT), /* IIN6 */
|
||||
ENDPOINT(7, BULK, OUT, &RX7STAT), /* BOUT7 */
|
||||
ENDPOINT(8, BULK, IN, &TX8STAT), /* BIN8 */
|
||||
ENDPOINT(9, INT, IN, &TX9STAT), /* IIN9 */
|
||||
ENDPOINT(10, BULK, OUT, &RX10STAT), /* BOUT10 */
|
||||
ENDPOINT(11, BULK, IN, &TX11STAT), /* BIN11 */
|
||||
ENDPOINT(12, INT, IN, &TX12STAT), /* IIN12 */
|
||||
ENDPOINT(13, BULK, OUT, &RX13STAT), /* BOUT13 */
|
||||
ENDPOINT(14, BULK, IN, &TX14STAT), /* BIN14 */
|
||||
ENDPOINT(15, INT, IN, &TX15STAT), /* IIN15 */
|
||||
};
|
||||
|
||||
static volatile bool set_address = false;
|
||||
static volatile bool set_configuration = false;
|
||||
|
||||
#undef ENDPOINT
|
||||
|
||||
static void setup_received(void)
|
||||
{
|
||||
static uint32_t setup_data[2];
|
||||
|
||||
logf("udc: setup");
|
||||
|
||||
/* copy setup data from packet */
|
||||
setup_data[0] = SETUP1;
|
||||
setup_data[1] = SETUP2;
|
||||
|
||||
/* clear all pending control transfers
|
||||
* do we need this here?
|
||||
*/
|
||||
|
||||
/* pass setup data to the upper layer */
|
||||
usb_core_control_request((struct usb_ctrlrequest*)setup_data);
|
||||
}
|
||||
|
||||
/* service ep0 IN transaction */
|
||||
static void ctr_write(void)
|
||||
static int max_pkt_size(struct endpoint_t *endp)
|
||||
{
|
||||
int xfer_size = (ctrlep[DIR_IN].cnt > 64) ? 64 : ctrlep[DIR_IN].cnt;
|
||||
switch(endp->type)
|
||||
{
|
||||
case USB_ENDPOINT_XFER_CONTROL: return 64;
|
||||
case USB_ENDPOINT_XFER_BULK: return usb_drv_port_speed() ? 512 : 64;
|
||||
case USB_ENDPOINT_XFER_INT: return usb_drv_port_speed() ? 1024 : 64;
|
||||
default: panicf("die"); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ep_write(struct endpoint_t *endp)
|
||||
{
|
||||
int xfer_size = MIN(max_pkt_size(endp), endp->cnt);
|
||||
unsigned int timeout = current_tick + HZ/10;
|
||||
|
||||
while (TX0BUF & TXFULL) /* TX0FULL flag */
|
||||
|
||||
while(TXBUF(endp) & TXFULL) /* TXFULL flag */
|
||||
{
|
||||
if(TIME_AFTER(current_tick, timeout))
|
||||
break;
|
||||
}
|
||||
|
||||
TX0STAT = xfer_size; /* size of the transfer */
|
||||
TX0DMALM_IADDR = (uint32_t)ctrlep[DIR_IN].buf; /* local buffer address */
|
||||
TX0DMAINCTL = DMA_START; /* start DMA */
|
||||
TX0CON &= ~TXNAK; /* clear NAK */
|
||||
|
||||
/* setup transfer size and DMA */
|
||||
TXSTAT(endp) = xfer_size;
|
||||
DMAINLMADDR(endp) = (uint32_t)endp->buf; /* local buffer address */
|
||||
DMAINCTL(endp) = DMA_START;
|
||||
/* Decrement by max packet size is intentional.
|
||||
* This way if we have final packet short one we will get negative len
|
||||
* after transfer, which in turn indicates we *don't* need to send
|
||||
|
|
@ -147,290 +153,141 @@ static void ctr_write(void)
|
|||
* get zero len after transfer which indicates we need to send
|
||||
* zero length packet to signal host end of the transfer.
|
||||
*/
|
||||
ctrlep[DIR_IN].cnt -= 64;
|
||||
ctrlep[DIR_IN].buf += xfer_size;
|
||||
endp->cnt -= max_pkt_size(endp);
|
||||
endp->buf += xfer_size;
|
||||
/* clear NAK */
|
||||
TXCON(endp) &= ~TXNAK;
|
||||
}
|
||||
|
||||
static void ctr_read(void)
|
||||
static void ep_read(struct endpoint_t *endp)
|
||||
{
|
||||
int xfer_size = RX0STAT & 0xffff;
|
||||
|
||||
/* clear NAK bit */
|
||||
RX0CON &= ~RXNAK;
|
||||
|
||||
ctrlep[DIR_OUT].cnt -= xfer_size;
|
||||
ctrlep[DIR_OUT].buf += xfer_size;
|
||||
|
||||
RX0DMAOUTLMADDR = (uint32_t)ctrlep[DIR_OUT].buf; /* buffer address */
|
||||
RX0DMACTLO = DMA_START; /* start DMA */
|
||||
/* setup DMA */
|
||||
DMAOUTLMADDR(endp) = (uint32_t)endp->buf; /* local buffer address */
|
||||
DMAOUTCTL(endp) = DMA_START;
|
||||
/* clear NAK */
|
||||
RXCON(endp) &= ~RXNAK;
|
||||
}
|
||||
|
||||
static void blk_write(int ep)
|
||||
static void in_intr(struct endpoint_t *endp)
|
||||
{
|
||||
int ep_num = EP_NUM(ep);
|
||||
int max = usb_drv_port_speed() ? 512 : 64;
|
||||
int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
|
||||
unsigned int timeout = current_tick + HZ/10;
|
||||
|
||||
while (BIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */
|
||||
uint32_t txstat = TXSTAT(endp);
|
||||
/* check if clear feature was sent by host */
|
||||
if(txstat & TXCFINT)
|
||||
{
|
||||
if(TIME_AFTER(current_tick, timeout))
|
||||
break;
|
||||
logf("clear_stall: %d", endp->ep_num);
|
||||
usb_drv_stall(endp->ep_num, false, true);
|
||||
}
|
||||
|
||||
BIN_TXSTAT(ep_num) = xfer_size; /* size */
|
||||
BIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
|
||||
BIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */
|
||||
BIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */
|
||||
|
||||
/* Decrement by max packet size is intentional.
|
||||
* This way if we have final packet short one we will get negative len
|
||||
* after transfer, which in turn indicates we *don't* need to send
|
||||
* zero length packet. If the final packet is max sized packet we will
|
||||
* get zero len after transfer which indicates we need to send
|
||||
* zero length packet to signal host end of the transfer.
|
||||
/* check if a transfer has finished */
|
||||
if(txstat & TXACK)
|
||||
{
|
||||
logf("udc: ack(%d)", endp->ep_num);
|
||||
/* finished ? */
|
||||
if(endp->cnt <= 0)
|
||||
{
|
||||
usb_core_transfer_complete(endp->ep_num, endp->dir, 0, endp->len);
|
||||
/* release semaphore for blocking transfer */
|
||||
if(endp->block)
|
||||
semaphore_release(&endp->complete);
|
||||
}
|
||||
else /* more data to send */
|
||||
ep_write(endp);
|
||||
}
|
||||
}
|
||||
|
||||
static void out_intr(struct endpoint_t *endp)
|
||||
{
|
||||
uint32_t rxstat = RXSTAT(endp);
|
||||
logf("udc: out intr(%d)", endp->ep_num);
|
||||
/* check if clear feature was sent by host */
|
||||
if(rxstat & RXCFINT)
|
||||
{
|
||||
logf("clear_stall: %d", endp->ep_num);
|
||||
usb_drv_stall(endp->ep_num, false, false);
|
||||
}
|
||||
/* check if a transfer has finished */
|
||||
if(rxstat & RXACK)
|
||||
{
|
||||
int xfer_size = rxstat & 0xffff;
|
||||
endp->cnt -= xfer_size;
|
||||
endp->buf += xfer_size;
|
||||
logf("udc: ack(%d) -> %d/%d", endp->ep_num, xfer_size, endp->cnt);
|
||||
/* finished ? */
|
||||
if(endp->cnt <= 0 || xfer_size < max_pkt_size(endp))
|
||||
usb_core_transfer_complete(endp->ep_num, endp->dir, 0, endp->len);
|
||||
else
|
||||
ep_read(endp);
|
||||
}
|
||||
}
|
||||
|
||||
static void udc_phy_reset(void)
|
||||
{
|
||||
DEV_CTL |= SOFT_POR;
|
||||
udelay(10000); /* min 10ms */
|
||||
DEV_CTL &= ~SOFT_POR;
|
||||
}
|
||||
|
||||
static void udc_soft_connect(void)
|
||||
{
|
||||
DEV_CTL |= CSR_DONE |
|
||||
DEV_SOFT_CN |
|
||||
DEV_SELF_PWR;
|
||||
}
|
||||
|
||||
static void udc_helper(void)
|
||||
{
|
||||
uint32_t dev_info = DEV_INFO;
|
||||
|
||||
/* This polls for DEV_EN bit set in DEV_INFO register
|
||||
* as well as tracks current requested configuration
|
||||
* (DEV_INFO [11:8]). On state change it notifies usb stack
|
||||
* about it.
|
||||
*/
|
||||
endpoints[ep_num].cnt -= max;
|
||||
endpoints[ep_num].buf += xfer_size;
|
||||
}
|
||||
|
||||
static void blk_read(int ep)
|
||||
{
|
||||
int ep_num = EP_NUM(ep);
|
||||
int xfer_size = BOUT_RXSTAT(ep_num) & 0xffff;
|
||||
|
||||
/* clear NAK bit */
|
||||
BOUT_RXCON(ep_num) &= ~RXNAK;
|
||||
|
||||
endpoints[ep_num].cnt -= xfer_size;
|
||||
endpoints[ep_num].buf += xfer_size;
|
||||
|
||||
BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf;
|
||||
BOUT_DMAOUTCTL(ep_num) = DMA_START;
|
||||
}
|
||||
/* SET ADDRESS request */
|
||||
if(!set_address)
|
||||
if(dev_info & 0x7f)
|
||||
{
|
||||
set_address = true;
|
||||
usb_core_notify_set_address(dev_info & 0x7f);
|
||||
}
|
||||
|
||||
static void int_write(int ep)
|
||||
{
|
||||
int ep_num = EP_NUM(ep);
|
||||
int max = usb_drv_port_speed() ? 1024 : 64;
|
||||
int xfer_size = (endpoints[ep_num].cnt > max) ? max : endpoints[ep_num].cnt;
|
||||
unsigned int timeout = current_tick + HZ/10;
|
||||
|
||||
while (IIN_TXBUF(ep_num) & TXFULL) /* TXFULL flag */
|
||||
{
|
||||
if(TIME_AFTER(current_tick, timeout))
|
||||
break;
|
||||
}
|
||||
|
||||
IIN_TXSTAT(ep_num) = xfer_size; /* size */
|
||||
IIN_DMAINLMADDR(ep_num) = (uint32_t)endpoints[ep_num].buf; /* buf address */
|
||||
IIN_DMAINCTL(ep_num) = DMA_START; /* start DMA */
|
||||
IIN_TXCON(ep_num) &= ~TXNAK; /* clear NAK */
|
||||
|
||||
/* Decrement by max packet size is intentional.
|
||||
* This way if we have final packet short one we will get negative len
|
||||
* after transfer, which in turn indicates we *don't* need to send
|
||||
* zero length packet. If the final packet is max sized packet we will
|
||||
* get zero len after transfer which indicates we need to send
|
||||
* zero length packet to signal host end of the transfer.
|
||||
*/
|
||||
endpoints[ep_num].cnt -= max;
|
||||
endpoints[ep_num].buf += xfer_size;
|
||||
}
|
||||
|
||||
/* UDC ISR function */
|
||||
void INT_UDC(void)
|
||||
{
|
||||
uint32_t txstat, rxstat;
|
||||
int tmp, ep_num;
|
||||
|
||||
/* read what caused UDC irq */
|
||||
uint32_t intsrc = INT2FLAG & 0x7fffff;
|
||||
|
||||
if (intsrc & SETUP_INTR) /* setup interrupt */
|
||||
{
|
||||
setup_received();
|
||||
}
|
||||
else if (intsrc & IN0_INTR) /* ep0 in interrupt */
|
||||
{
|
||||
txstat = TX0STAT; /* read clears flags */
|
||||
|
||||
/* TODO handle errors */
|
||||
if (txstat & TXACK) /* check TxACK flag */
|
||||
/* SET CONFIGURATION request */
|
||||
if(!set_configuration)
|
||||
if(dev_info & DEV_EN)
|
||||
{
|
||||
if (ctrlep[DIR_IN].cnt >= 0)
|
||||
{
|
||||
/* we still have data to send (or ZLP) */
|
||||
ctr_write();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* final ack received */
|
||||
usb_core_transfer_complete(0, /* ep */
|
||||
USB_DIR_IN, /* dir */
|
||||
0, /* status */
|
||||
ctrlep[DIR_IN].len); /* length */
|
||||
|
||||
/* release semaphore for blocking transfer */
|
||||
if (ctrlep[DIR_IN].block)
|
||||
semaphore_release(&ctrlep[DIR_IN].complete);
|
||||
}
|
||||
set_configuration = true;
|
||||
usb_core_notify_set_config(((dev_info >> 7) & 0xf) + 1);
|
||||
}
|
||||
}
|
||||
else if (intsrc & OUT0_INTR) /* ep0 out interrupt */
|
||||
{
|
||||
rxstat = RX0STAT;
|
||||
|
||||
/* TODO handle errors */
|
||||
if (rxstat & RXACK) /* RxACK */
|
||||
{
|
||||
if (ctrlep[DIR_OUT].cnt > 0)
|
||||
ctr_read();
|
||||
else
|
||||
usb_core_transfer_complete(0, /* ep */
|
||||
USB_DIR_OUT, /* dir */
|
||||
0, /* status */
|
||||
ctrlep[DIR_OUT].len); /* length */
|
||||
}
|
||||
}
|
||||
else if (intsrc & USBRST_INTR) /* usb reset */
|
||||
{
|
||||
usb_drv_init();
|
||||
}
|
||||
else if (intsrc & RESUME_INTR) /* usb resume */
|
||||
{
|
||||
TX0CON |= TXCLR; /* TxClr */
|
||||
TX0CON &= ~TXCLR;
|
||||
RX0CON |= RXCLR; /* RxClr */
|
||||
RX0CON &= ~RXCLR;
|
||||
}
|
||||
else if (intsrc & SUSP_INTR) /* usb suspend */
|
||||
{
|
||||
}
|
||||
else if (intsrc & CONN_INTR) /* usb connect */
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
/* lets figure out which ep generated irq */
|
||||
tmp = intsrc >> 7;
|
||||
for (ep_num=1; ep_num < 15; ep_num++)
|
||||
{
|
||||
tmp >>= ep_num;
|
||||
if (tmp & 0x01)
|
||||
break;
|
||||
}
|
||||
|
||||
if (intsrc & ((1<<8)|(1<<11)|(1<<14)|(1<<17)|(1<<20)))
|
||||
{
|
||||
/* bulk out */
|
||||
rxstat = BOUT_RXSTAT(ep_num);
|
||||
|
||||
/* TODO handle errors */
|
||||
if (rxstat & (1<<18)) /* RxACK */
|
||||
{
|
||||
if (endpoints[ep_num].cnt > 0)
|
||||
blk_read(ep_num);
|
||||
else
|
||||
usb_core_transfer_complete(ep_num, /* ep */
|
||||
USB_DIR_OUT, /* dir */
|
||||
0, /* status */
|
||||
endpoints[ep_num].len); /* length */
|
||||
}
|
||||
}
|
||||
else if (intsrc & ((1<<9)|(1<<12)|(1<<15)|(1<<18)|(1<<21)))
|
||||
{
|
||||
/* bulk in */
|
||||
txstat = BIN_TXSTAT(ep_num);
|
||||
|
||||
/* TODO handle errors */
|
||||
if (txstat & (1<<18)) /* check TxACK flag */
|
||||
{
|
||||
if (endpoints[ep_num].cnt >= 0)
|
||||
{
|
||||
/* we still have data to send (or ZLP) */
|
||||
blk_write(ep_num);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* final ack received */
|
||||
usb_core_transfer_complete(ep_num, /* ep */
|
||||
USB_DIR_IN, /* dir */
|
||||
0, /* status */
|
||||
endpoints[ep_num].len); /* length */
|
||||
|
||||
/* release semaphore for blocking transfer */
|
||||
if (endpoints[ep_num].block)
|
||||
semaphore_release(&endpoints[ep_num].complete);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (intsrc & ((1<<10)|(1<13)|(1<<16)|(1<<19)|(1<<22)))
|
||||
{
|
||||
/* int in */
|
||||
txstat = IIN_TXSTAT(ep_num);
|
||||
|
||||
/* TODO handle errors */
|
||||
if (txstat & TXACK) /* check TxACK flag */
|
||||
{
|
||||
if (endpoints[ep_num].cnt >= 0)
|
||||
{
|
||||
/* we still have data to send (or ZLP) */
|
||||
int_write(ep_num);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* final ack received */
|
||||
usb_core_transfer_complete(ep_num, /* ep */
|
||||
USB_DIR_IN, /* dir */
|
||||
0, /* status */
|
||||
endpoints[ep_num].len); /* length */
|
||||
|
||||
/* release semaphore for blocking transfer */
|
||||
if (endpoints[ep_num].block)
|
||||
semaphore_release(&endpoints[ep_num].complete);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return port speed FS=0, HS=1 */
|
||||
int usb_drv_port_speed(void)
|
||||
{
|
||||
return ((DEV_INFO & DEV_SPEED) == 0) ? 0 : 1;
|
||||
return (DEV_INFO & DEV_SPEED) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* Reserve endpoint */
|
||||
int usb_drv_request_endpoint(int type, int dir)
|
||||
{
|
||||
int ep_num, ep_dir;
|
||||
int ep_type;
|
||||
logf("req: %s %s", XFER_DIR_STR(dir), XFER_TYPE_STR(type));
|
||||
|
||||
/* Safety */
|
||||
ep_dir = EP_DIR(dir);
|
||||
ep_type = type & USB_ENDPOINT_XFERTYPE_MASK;
|
||||
|
||||
logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type));
|
||||
|
||||
/* Find an available ep/dir pair */
|
||||
for (ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++)
|
||||
for(int ep_num = 1; ep_num<USB_NUM_ENDPOINTS;ep_num++)
|
||||
{
|
||||
struct endpoint_t* endpoint = &endpoints[ep_num];
|
||||
|
||||
if (endpoint->type == ep_type &&
|
||||
endpoint->dir == ep_dir &&
|
||||
!endpoint->allocated)
|
||||
{
|
||||
/* mark endpoint as taken */
|
||||
endpoint->allocated = true;
|
||||
|
||||
/* enable interrupt from this endpoint */
|
||||
EN_INT |= (1<<(ep_num+7));
|
||||
|
||||
logf("add: ep%d %s", ep_num, XFER_DIR_STR(ep_dir));
|
||||
return (ep_num | (dir & USB_ENDPOINT_DIR_MASK));
|
||||
}
|
||||
struct endpoint_t *endp = &endpoints[ep_num];
|
||||
|
||||
if(endp->allocated || endp->type != type || endp->dir != dir)
|
||||
continue;
|
||||
/* allocate endpoint and enable interrupt */
|
||||
endp->allocated = true;
|
||||
if(dir == USB_DIR_IN)
|
||||
TXCON(endp) = (ep_num << 8) | TXEPEN | TXNAK | TXACKINTEN | TXCFINTE;
|
||||
else
|
||||
RXCON(endp) = (ep_num << 8) | RXEPEN | RXNAK | RXACKINTEN | RXCFINTE | RXERRINTEN;
|
||||
EN_INT |= 1 << (ep_num + 7);
|
||||
|
||||
logf("add: ep%d %s", ep_num, XFER_DIR_STR(dir));
|
||||
return ep_num | dir;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -439,14 +296,12 @@ int usb_drv_request_endpoint(int type, int dir)
|
|||
void usb_drv_release_endpoint(int ep)
|
||||
{
|
||||
int ep_num = EP_NUM(ep);
|
||||
int ep_dir = EP_DIR(ep);
|
||||
(void) ep_dir;
|
||||
|
||||
logf("rel: ep%d %s", ep_num, XFER_DIR_STR(ep_dir));
|
||||
logf("rel: ep%d", ep_num);
|
||||
endpoints[ep_num].allocated = false;
|
||||
|
||||
|
||||
/* disable interrupt from this endpoint */
|
||||
EN_INT &= ~(1<<(ep_num+7));
|
||||
EN_INT &= ~(1 << (ep_num + 7));
|
||||
}
|
||||
|
||||
/* Set the address (usually it's in a register).
|
||||
|
|
@ -463,39 +318,25 @@ void usb_drv_set_address(int address)
|
|||
|
||||
static int _usb_drv_send(int endpoint, void *ptr, int length, bool block)
|
||||
{
|
||||
logf("udc: send(%x)", endpoint);
|
||||
struct endpoint_t *ep;
|
||||
int ep_num = EP_NUM(endpoint);
|
||||
|
||||
|
||||
if (ep_num == 0)
|
||||
ep = &ctrlep[DIR_IN];
|
||||
else
|
||||
ep = &endpoints[ep_num];
|
||||
|
||||
/* for send transfers, make sure the data is committed */
|
||||
commit_discard_dcache_range(ptr, length);
|
||||
ep->buf = ptr;
|
||||
ep->len = ep->cnt = length;
|
||||
|
||||
if (block)
|
||||
ep->block = true;
|
||||
else
|
||||
ep->block = false;
|
||||
|
||||
switch (ep->type)
|
||||
{
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
ctr_write();
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
blk_write(ep_num);
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
int_write(ep_num);
|
||||
break;
|
||||
}
|
||||
|
||||
if (block)
|
||||
/* wait for transfer to end */
|
||||
ep->block = block;
|
||||
|
||||
ep_write(ep);
|
||||
|
||||
/* wait for transfer to end */
|
||||
if(block)
|
||||
semaphore_wait(&ep->complete, TIMEOUT_BLOCK);
|
||||
|
||||
return 0;
|
||||
|
|
@ -516,28 +357,20 @@ int usb_drv_send_nonblocking(int endpoint, void *ptr, int length)
|
|||
/* Setup a receive transfer. (non blocking) */
|
||||
int usb_drv_recv(int endpoint, void* ptr, int length)
|
||||
{
|
||||
logf("udc: recv(%x)", endpoint);
|
||||
struct endpoint_t *ep;
|
||||
int ep_num = EP_NUM(endpoint);
|
||||
|
||||
if (ep_num == 0)
|
||||
{
|
||||
|
||||
if(ep_num == 0)
|
||||
ep = &ctrlep[DIR_OUT];
|
||||
|
||||
ctr_read();
|
||||
}
|
||||
else
|
||||
{
|
||||
ep = &endpoints[ep_num];
|
||||
|
||||
/* clear NAK bit */
|
||||
BOUT_RXCON(ep_num) &= ~RXNAK;
|
||||
BOUT_DMAOUTLMADDR(ep_num) = (uint32_t)ptr;
|
||||
BOUT_DMAOUTCTL(ep_num) = DMA_START;
|
||||
}
|
||||
|
||||
|
||||
/* for recv, discard the cache lines related to the buffer */
|
||||
commit_discard_dcache_range(ptr, length);
|
||||
ep->buf = ptr;
|
||||
ep->len = ep->cnt = length;
|
||||
|
||||
ep_read(ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -560,173 +393,54 @@ void usb_drv_set_test_mode(int mode)
|
|||
/* Check if endpoint is in stall state */
|
||||
bool usb_drv_stalled(int endpoint, bool in)
|
||||
{
|
||||
int ep_num = EP_NUM(endpoint);
|
||||
struct endpoint_t *endp = &endpoints[EP_NUM(endpoint)];
|
||||
|
||||
switch (endpoints[ep_num].type)
|
||||
{
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
if (in)
|
||||
return (TX0CON & TXSTALL) ? true : false;
|
||||
else
|
||||
return (RX0CON & RXSTALL) ? true : false;
|
||||
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
if (in)
|
||||
return (BIN_TXCON(ep_num) & TXSTALL) ? true : false;
|
||||
else
|
||||
return (BOUT_RXCON(ep_num) & RXSTALL) ? true : false;
|
||||
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
if (in)
|
||||
return (IIN_TXCON(ep_num) & TXSTALL) ? true : false;
|
||||
else
|
||||
return false; /* we don't have such endpoint anyway */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
if(in)
|
||||
return !!(TXCON(endp) & TXSTALL);
|
||||
else
|
||||
return !!(RXCON(endp) & RXSTALL);
|
||||
}
|
||||
|
||||
/* Stall the endpoint. Usually set a flag in the controller */
|
||||
void usb_drv_stall(int endpoint, bool stall, bool in)
|
||||
{
|
||||
int ep_num = EP_NUM(endpoint);
|
||||
|
||||
switch (endpoints[ep_num].type)
|
||||
struct endpoint_t *endp = &endpoints[EP_NUM(endpoint)];
|
||||
if(in)
|
||||
{
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
if (in)
|
||||
{
|
||||
if (stall)
|
||||
TX0CON |= TXSTALL;
|
||||
else
|
||||
TX0CON &= ~TXSTALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stall)
|
||||
RX0CON |= RXSTALL;
|
||||
else
|
||||
RX0CON &= ~RXSTALL; /* doc says Auto clear by UDC 2.0 */
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
if (in)
|
||||
{
|
||||
if (stall)
|
||||
BIN_TXCON(ep_num) |= TXSTALL;
|
||||
else
|
||||
BIN_TXCON(ep_num) &= ~TXSTALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stall)
|
||||
BOUT_RXCON(ep_num) |= RXSTALL;
|
||||
else
|
||||
BOUT_RXCON(ep_num) &= ~RXSTALL;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
if (in)
|
||||
{
|
||||
if (stall)
|
||||
IIN_TXCON(ep_num) |= TXSTALL;
|
||||
else
|
||||
IIN_TXCON(ep_num) &= ~TXSTALL;
|
||||
}
|
||||
break;
|
||||
if(stall)
|
||||
TXCON(endp) |= TXSTALL;
|
||||
else
|
||||
TXCON(endp) &= ~TXSTALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(stall)
|
||||
RXCON(endp) |= RXSTALL;
|
||||
else
|
||||
RXCON(endp) &= ~RXSTALL;
|
||||
}
|
||||
}
|
||||
|
||||
/* one time init (once per connection) - basicaly enable usb core */
|
||||
void usb_drv_init(void)
|
||||
{
|
||||
int ep_num;
|
||||
|
||||
/* enable USB clock */
|
||||
SCU_CLKCFG &= ~CLKCFG_UDC;
|
||||
|
||||
/* 1. do soft disconnect */
|
||||
DEV_CTL = DEV_SELF_PWR;
|
||||
|
||||
/* 2. do power on reset to PHY */
|
||||
DEV_CTL = DEV_SELF_PWR |
|
||||
SOFT_POR;
|
||||
|
||||
/* 3. wait more than 10ms */
|
||||
udelay(20000);
|
||||
|
||||
/* 4. clear SOFT_POR bit */
|
||||
DEV_CTL &= ~SOFT_POR;
|
||||
|
||||
/* 5. configure minimal EN_INT */
|
||||
EN_INT = EN_SUSP_INTR | /* Enable Suspend Interrupt */
|
||||
EN_RESUME_INTR | /* Enable Resume Interrupt */
|
||||
EN_USBRST_INTR | /* Enable USB Reset Interrupt */
|
||||
EN_OUT0_INTR | /* Enable OUT Token receive Interrupt EP0 */
|
||||
EN_IN0_INTR | /* Enable IN Token transmits Interrupt EP0 */
|
||||
EN_SETUP_INTR; /* Enable SETUP Packet Receive Interrupt */
|
||||
|
||||
/* 6. configure INTCON */
|
||||
INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
|
||||
UDC_INTEN; /* enable EP0 interrupts */
|
||||
|
||||
/* 7. configure EP0 control registers */
|
||||
TX0CON = TXACKINTEN | /* Set as one to enable the EP0 tx irq */
|
||||
TXNAK; /* Set as one to response NAK handshake */
|
||||
|
||||
RX0CON = RXACKINTEN |
|
||||
RXEPEN | /* Endpoint 0 Enable. When cleared the endpoint does
|
||||
* not respond to an SETUP or OUT token
|
||||
*/
|
||||
|
||||
RXNAK; /* Set as one to response NAK handshake */
|
||||
|
||||
/* 8. write final bits to DEV_CTL */
|
||||
DEV_CTL = CSR_DONE | /* Configure CSR done */
|
||||
DEV_PHY16BIT | /* 16-bit data path enabled. udc_clk = 30MHz */
|
||||
DEV_SOFT_CN | /* Device soft connect */
|
||||
DEV_SELF_PWR; /* Device self power */
|
||||
|
||||
/* init semaphore of ep0 */
|
||||
semaphore_init(&ctrlep[DIR_OUT].complete, 1, 0);
|
||||
semaphore_init(&ctrlep[DIR_IN].complete, 1, 0);
|
||||
|
||||
for (ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
|
||||
{
|
||||
|
||||
for(int ep_num = 1; ep_num < USB_NUM_ENDPOINTS; ep_num++)
|
||||
semaphore_init(&endpoints[ep_num].complete, 1, 0);
|
||||
|
||||
if (ep_num%3 == 0) /* IIN 3, 6, 9, 12, 15 */
|
||||
{
|
||||
IIN_TXCON(ep_num) |= (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */
|
||||
}
|
||||
else if (ep_num%3 == 1) /* BOUT 1, 4, 7, 10, 13 */
|
||||
{
|
||||
BOUT_RXCON(ep_num) |= (ep_num<<8)|RXEPEN|RXNAK; /* ep_num, NAK, enable */
|
||||
}
|
||||
else if (ep_num%3 == 2) /* BIN 2, 5, 8, 11, 14 */
|
||||
{
|
||||
BIN_TXCON(ep_num) |= (ep_num<<8)|TXEPEN|TXNAK; /* ep_num, enable, NAK */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* turn off usb core */
|
||||
void usb_drv_exit(void)
|
||||
{
|
||||
DEV_CTL = DEV_SELF_PWR;
|
||||
|
||||
|
||||
/* disable USB interrupts in interrupt controller */
|
||||
INTC_IMR &= ~IRQ_ARM_UDC;
|
||||
INTC_IECR &= ~IRQ_ARM_UDC;
|
||||
|
||||
|
||||
/* we cannot disable UDC clock since this causes data abort
|
||||
* when reading DEV_INFO in order to check usb connect event
|
||||
*/
|
||||
|
|
@ -734,9 +448,94 @@ void usb_drv_exit(void)
|
|||
|
||||
int usb_detect(void)
|
||||
{
|
||||
if (DEV_INFO & VBUS_STS)
|
||||
if(DEV_INFO & VBUS_STS)
|
||||
return USB_INSERTED;
|
||||
else
|
||||
return USB_EXTRACTED;
|
||||
}
|
||||
|
||||
/* UDC ISR function */
|
||||
void INT_UDC(void)
|
||||
{
|
||||
/* read what caused UDC irq */
|
||||
uint32_t intsrc = INT2FLAG & 0x7fffff;
|
||||
|
||||
if(intsrc & USBRST_INTR) /* usb reset */
|
||||
{
|
||||
logf("udc_int: reset, %ld", current_tick);
|
||||
|
||||
EN_INT = EN_SUSP_INTR | /* Enable Suspend Irq */
|
||||
EN_RESUME_INTR | /* Enable Resume Irq */
|
||||
EN_USBRST_INTR | /* Enable USB Reset Irq */
|
||||
EN_OUT0_INTR | /* Enable OUT Token receive Irq EP0 */
|
||||
EN_IN0_INTR | /* Enable IN Token transmit Irq EP0 */
|
||||
EN_SETUP_INTR; /* Enable SETUP Packet Receive Irq */
|
||||
|
||||
INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
|
||||
UDC_INTEN; /* enable EP0 irqs */
|
||||
|
||||
TX0CON = TXACKINTEN | /* Set as one to enable the EP0 tx irq */
|
||||
TXNAK; /* Set as one to response NAK handshake */
|
||||
|
||||
RX0CON = RXACKINTEN |
|
||||
RXEPEN | /* Endpoint 0 Enable. When cleared the
|
||||
* endpoint does not respond to an SETUP
|
||||
* or OUT token */
|
||||
RXNAK; /* Set as one to response NAK handshake */
|
||||
|
||||
set_address = false;
|
||||
set_configuration = false;
|
||||
}
|
||||
/* This needs to be processed AFTER usb reset */
|
||||
udc_helper();
|
||||
|
||||
if(intsrc & SETUP_INTR) /* setup interrupt */
|
||||
{
|
||||
setup_received();
|
||||
}
|
||||
if(intsrc & IN0_INTR)
|
||||
{
|
||||
/* EP0 IN done */
|
||||
in_intr(&ctrlep[DIR_IN]);
|
||||
}
|
||||
if(intsrc & OUT0_INTR)
|
||||
{
|
||||
/* EP0 OUT done */
|
||||
out_intr(&ctrlep[DIR_OUT]);
|
||||
}
|
||||
if(intsrc & USBRST_INTR)
|
||||
{
|
||||
/* usb reset */
|
||||
usb_drv_init();
|
||||
}
|
||||
if(intsrc & RESUME_INTR)
|
||||
{
|
||||
/* usb resume */
|
||||
TX0CON |= TXCLR; /* TxClr */
|
||||
TX0CON &= ~TXCLR;
|
||||
RX0CON |= RXCLR; /* RxClr */
|
||||
RX0CON &= ~RXCLR;
|
||||
}
|
||||
if(intsrc & SUSP_INTR)
|
||||
{
|
||||
/* usb suspend */
|
||||
}
|
||||
if(intsrc & CONN_INTR)
|
||||
{
|
||||
/* usb connect */
|
||||
udc_phy_reset();
|
||||
udelay(10000); /* wait at least 10ms */
|
||||
udc_soft_connect();
|
||||
}
|
||||
/* other endpoints */
|
||||
for(int ep_num = 1; ep_num < 16; ep_num++)
|
||||
{
|
||||
if(!(intsrc & (1 << (ep_num + 7))))
|
||||
continue;
|
||||
struct endpoint_t *endp = &endpoints[ep_num];
|
||||
if(endp->dir == USB_DIR_IN)
|
||||
in_intr(endp);
|
||||
else
|
||||
out_intr(endp);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,20 @@ int usb_status = USB_EXTRACTED;
|
|||
|
||||
void usb_init_device(void)
|
||||
{
|
||||
/* enable UDC interrupt */
|
||||
INTC_IMR |= (1<<16);
|
||||
INTC_IECR |= (1<<16);
|
||||
|
||||
EN_INT = EN_SUSP_INTR | /* Enable Suspend Interrupt */
|
||||
EN_RESUME_INTR | /* Enable Resume Interrupt */
|
||||
EN_USBRST_INTR | /* Enable USB Reset Interrupt */
|
||||
EN_OUT0_INTR | /* Enable OUT Token receive Interrupt EP0 */
|
||||
EN_IN0_INTR | /* Enable IN Token transmits Interrupt EP0 */
|
||||
EN_SETUP_INTR; /* Enable SETUP Packet Receive Interrupt */
|
||||
|
||||
/* configure INTCON */
|
||||
INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
|
||||
UDC_INTEN; /* enable EP0 interrupts */
|
||||
}
|
||||
|
||||
void usb_attach(void)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue