首页 > 代码库 > MTK 6752/6732支持6630
MTK 6752/6732支持6630
需要两方面处理:
一 根据原理图配置好GPIO
二 修改代码,有如下几只文件需要修改:
1 alps/mediatek/config/{project}/ProjectConfig.mk添加如下option:
CUSTOM_HAL_COMBO=mt6630
CUSTOM_HAL_ANT=mt6630_ant_m1
MTK_COMBO_CORE_DUMP_SUPPORT=no
MTK_COMBO_QUICK_SLEEP_SUPPORT=no
MTK_COMBO_CHIP = MT6630
MTK_WLAN_CHIP=MT6630
MTK_BT_CHIP = MTK_MT6630
MTK_GPS_CHIP = MTK_GPS_MT6630
MTK_FM_CHIP=MT6630_FM
(注意:最好double check原ProjectConfig文件是否已经存在某项option,如果存在且取值一样,则不需要添加;如果只是值不同,则修改为上述值)
2 alps/mediatek/config/{project}/init.project.rc factory_init.project.rc meta_init.project.rc这三只文件
统一作如下2处修改:
service conn_launcher /system/bin/logwrapper /system/bin/6620_launcher -p /system/etc/firmware/
改为:
service 66xx_launcher /system/bin/logwrapper /system/bin/6620_launcher -m 4 -p /system/etc/firmware/
在文件末尾添加:
service autokd /system/bin/autokd
class core
user system
group nvram system
3 alps\mediatek\config\{project}\autoconfig\kconfig\project文件末尾添加:
CONFIG_SDIOAUTOK_SUPPORT=y
4 alps\mediatek\custom\{project}\kernel\core\src\board-custom.h文件作如下3处改动:
//#define CFG_DEV_MSDC3
改为:
#define CFG_DEV_MSDC3
#define CONFIG_MTK_COMBO_SDIO_SLOT (3)
改为:
#define CONFIG_MTK_WCN_CMB_SDIO_SLOT (3)
#undef CONFIG_MTK_COMBO_SDIO_SLOT
改为:
#undef CONFIG_MTK_WCN_CMB_SDIO_SLOT
5 alps\mediatek\custom\{project}\kernel\core\src\board.c文件,因改动内容较多,
最好整个将文件替换为如下内容:
/* system header files */
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include <linux/mtd/nand.h>
#include <asm/irq.h>
#include <asm/io.h>
//#include <asm/mach-types.h>
//#include <asm/mach/arch.h>
//#include <asm/mach/irq.h>
//#include <asm/mach/map.h>
//#include <asm/mach/time.h>
//#include <asm/setup.h>
#include <mach/system.h>
#include <mach/board.h>
#include <mach/hardware.h>
#include <mach/mt_gpio.h>
#include <mach/mt_bt.h>
#include <mach/eint.h>
#include <mach/mtk_rtc.h>
#include <mach/mt_typedefs.h>
// Fix-me: marked for early porting
#include <cust_gpio_usage.h>
#include <cust_eint.h>
#define CONFIG_EINT_DEVICE_TREE 0
#if CONFIG_EINT_DEVICE_TREE
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/irqreturn.h>
static atomic_t wifi_irq_flag;
static unsigned int wifi_irq = 0;
#endif
#include "board-custom.h"
#if defined(CONFIG_MTK_COMBO) || defined(CONFIG_MTK_COMBO_MODULE)
#include <mach/mtk_wcn_cmb_stub.h>
#endif
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT)
static sdio_irq_handler_t mtk_wcn_cmb_sdio_eirq_handler = NULL;
int mtk_wcn_sdio_irq_flag_set (int falg);
static atomic_t sdio_irq_enable_flag;
static pm_callback_t mtk_wcn_cmb_sdio_pm_cb = NULL;
static void *mtk_wcn_cmb_sdio_pm_data = http://www.mamicode.com/NULL;
static void *mtk_wcn_cmb_sdio_eirq_data = http://www.mamicode.com/NULL;
const static u32 mtk_wcn_cmb_sdio_eint_pin = GPIO_WIFI_EINT_PIN;
const static u32 mtk_wcn_cmb_sdio_eint_num = CUST_EINT_WIFI_NUM;
const static u32 mtk_wcn_cmb_sdio_eint_m_eint = GPIO_WIFI_EINT_PIN_M_EINT;
const static u32 mtk_wcn_cmb_sdio_eint_m_gpio = GPIO_WIFI_EINT_PIN_M_GPIO;
/*
index: port number of combo chip (1:SDIO1, 2:SDIO2, no SDIO0)
value: slot power status of (0:off, 1:on, 0xFF:invalid)
*/
#if (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 0)
static unsigned char combo_port_pwr_map[4] = {0x0, 0xFF, 0xFF, 0xFF};
#elif (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 1)
static unsigned char combo_port_pwr_map[4] = {0xFF, 0x0, 0xFF, 0xFF};
#elif (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 2)
static unsigned char combo_port_pwr_map[4] = {0xFF, 0xFF, 0x0, 0xFF};
#elif (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 3)
static unsigned char combo_port_pwr_map[4] = {0xFF, 0xFF, 0xFF, 0x0};
#else
#error "unsupported CONFIG_MTK_WCN_CMB_SDIO_SLOT" CONFIG_MTK_WCN_CMB_SDIO_SLOT
#endif
#else
/*standalone chip‘s structure should be add here*/
#endif
/*=======================================================================*/
/* Board Specific Devices Power Management */
/*=======================================================================*/
extern kal_bool pmic_chrdet_status(void);
void mt_power_off(void)
{
printk("mt_power_off\n");
/* pull PWRBB low */
/*Hong-Rong: FIXME for early porting*/
rtc_bbpu_power_down();
while (1) {
#if defined(CONFIG_POWER_EXT)
//EVB
printk("EVB without charger\n");
#else
//Phone
printk("Phone with charger\n");
if (pmic_chrdet_status() == KAL_TRUE)
arch_reset(0, "power_off_with_charger");
#endif
}
}
/*=======================================================================*/
/* Board Specific Devices */
/*=======================================================================*/
/*GPS driver*/
/*FIXME: remove mt3326 notation */
struct mt3326_gps_hardware mt3326_gps_hw = {
.ext_power_on = NULL,
.ext_power_off = NULL,
};
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT)
static void mtk_wcn_cmb_sdio_enable_eirq(void)
{
#if CONFIG_EINT_DEVICE_TREE
if(!atomic_read(&wifi_irq_flag))
{
printk(KERN_DEBUG "wifi eint has been enabled\n");;
}
else
{
enable_irq(wifi_irq);
atomic_dec(&wifi_irq_flag);
//printk(KERN_DEBUG " enable WIFI EINT irq %d !!\n",wifi_irq);
}
#else
mt_eint_unmask(mtk_wcn_cmb_sdio_eint_num);/* CUST_EINT_WIFI_NUM */
#endif
}
static void mtk_wcn_cmb_sdio_disable_eirq(void)
{
#if CONFIG_EINT_DEVICE_TREE
if(atomic_read(&wifi_irq_flag))
{
printk(KERN_DEBUG "wifi eint has been disabled!\n");;
}
else
{
disable_irq_nosync(wifi_irq);
atomic_inc(&wifi_irq_flag);
//printk(KERN_DEBUG "disable WIFI EINT irq %d !!\n",wifi_irq);
}
#else
mt_eint_mask(mtk_wcn_cmb_sdio_eint_num); /* CUST_EINT_WIFI_NUM */
#endif
}
#if CONFIG_EINT_DEVICE_TREE
irqreturn_t mtk_wcn_cmb_sdio_eirq_handler_stub(int irq,void *data)
{
if ((NULL != mtk_wcn_cmb_sdio_eirq_handler) && (0 != atomic_read(&sdio_irq_enable_flag))) {
mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data);
}
return IRQ_HANDLED;
}
#else
static void mtk_wcn_cmb_sdio_eirq_handler_stub(void)
{
if ((NULL != mtk_wcn_cmb_sdio_eirq_handler) && (0 != atomic_read(&sdio_irq_enable_flag))) {
mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data);
}
}
#endif
static void mtk_wcn_cmb_sdio_request_eirq(sdio_irq_handler_t irq_handler, void *data)
{
#if CONFIG_EINT_DEVICE_TREE
struct device_node *node;
u32 ints[2] = {0,0};
int ret = -EINVAL;
#endif
printk( KERN_INFO "enter %s\n", __func__);
mtk_wcn_sdio_irq_flag_set (0);
mtk_wcn_cmb_sdio_eirq_data = data;
mtk_wcn_cmb_sdio_eirq_handler = irq_handler;
#if 1
#if CONFIG_EINT_DEVICE_TREE
node = of_find_compatible_node(NULL, NULL, "mediatek, WIFI-eint");
if(node) {
of_property_read_u32_array(node, "debounce", ints, ARRAY_SIZE(ints));
mt_gpio_set_debounce(ints[0], ints[1]);
wifi_irq = irq_of_parse_and_map(node, 0);
ret = request_irq(wifi_irq, mtk_wcn_cmb_sdio_eirq_handler_stub, IRQF_TRIGGER_NONE,"WIFI-eint", NULL);
printk(KERN_DEBUG "WIFI EINT irq %d !!\n",wifi_irq);
atomic_set(&wifi_irq_flag, 0);/*default: irq enable*/
if(ret)
printk(KERN_ERR "WIFI EINT IRQ LINE NOT AVAILABLE!!\n");
else {
mtk_wcn_cmb_sdio_disable_eirq();/*not ,chip state is power off*/
}
}
else
printk(KERN_ERR "[%s] can‘t find wifi eint compatible node\n",__func__);
#else
mt_eint_registration(mtk_wcn_cmb_sdio_eint_num,
CUST_EINT_WIFI_TYPE,
mtk_wcn_cmb_sdio_eirq_handler_stub,
0);
#endif
#else
{
int i_ret = 0;
i_ret = request_irq(mtk_wcn_cmb_sdio_eint_num,
(irq_handler_t)mtk_wcn_cmb_sdio_eirq_handler_stub,
IRQF_TRIGGER_LOW,
"SDIO_EXT_IRQ",
NULL);
if (i_ret)
printk( KERN_ERR "request_irq for SDIO ext IRQ failed, i_ret(%d)\n", i_ret);
else
printk( KERN_ERR "request_irq for SDIO ext IRQ succeed, i_ret(%d)\n", i_ret);
}
#endif
#if CONFIG_EINT_DEVICE_TREE
#else
mt_eint_mask(mtk_wcn_cmb_sdio_eint_num);/*CUST_EINT_WIFI_NUM */
#endif
printk(KERN_INFO "exit %s\n", __func__);
}
static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data)
{
printk( KERN_INFO "mtk_wcn_cmb_sdio_register_pm (0x%p, 0x%p)\n", pm_cb, data);
/* register pm change callback */
mtk_wcn_cmb_sdio_pm_cb = pm_cb;
mtk_wcn_cmb_sdio_pm_data = http://www.mamicode.com/data;
}
static void mtk_wcn_cmb_sdio_on (int sdio_port_num) {
pm_message_t state = { .event = PM_EVENT_USER_RESUME };
printk(KERN_INFO "mtk_wcn_cmb_sdio_on (%d) \n", sdio_port_num);
/* 1. disable sdio eirq */
mtk_wcn_cmb_sdio_disable_eirq();
mt_set_gpio_pull_enable(mtk_wcn_cmb_sdio_eint_pin, GPIO_PULL_DISABLE); /* GPIO_WIFI_EINT_PIN */
mt_set_gpio_mode(mtk_wcn_cmb_sdio_eint_pin, mtk_wcn_cmb_sdio_eint_m_eint); /* EINT mode */
/* 2. call sd callback */
if (mtk_wcn_cmb_sdio_pm_cb) {
//printk(KERN_INFO "mtk_wcn_cmb_sdio_pm_cb(PM_EVENT_USER_RESUME, 0x%p, 0x%p) \n", mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data);
mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data);
}
else {
printk(KERN_WARNING "mtk_wcn_cmb_sdio_on no sd callback!!\n");
}
}
static void mtk_wcn_cmb_sdio_off (int sdio_port_num) {
pm_message_t state = { .event = PM_EVENT_USER_SUSPEND };
printk(KERN_INFO "mtk_wcn_cmb_sdio_off (%d) \n", sdio_port_num);
/* 1. call sd callback */
if (mtk_wcn_cmb_sdio_pm_cb) {
//printk(KERN_INFO "mtk_wcn_cmb_sdio_off(PM_EVENT_USER_SUSPEND, 0x%p, 0x%p) \n", mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data);
mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data);
}
else {
printk(KERN_WARNING "mtk_wcn_cmb_sdio_off no sd callback!!\n");
}
/* 2. disable sdio eirq */
mtk_wcn_cmb_sdio_disable_eirq();
/*printk(KERN_INFO "[mt6620] set WIFI_EINT input pull down\n");*/
mt_set_gpio_mode(mtk_wcn_cmb_sdio_eint_pin, mtk_wcn_cmb_sdio_eint_m_gpio); /* GPIO mode */
mt_set_gpio_dir(mtk_wcn_cmb_sdio_eint_pin, GPIO_DIR_IN);
mt_set_gpio_pull_select(mtk_wcn_cmb_sdio_eint_pin, GPIO_PULL_UP);
mt_set_gpio_pull_enable(mtk_wcn_cmb_sdio_eint_pin, GPIO_PULL_ENABLE);
}
int board_sdio_ctrl (unsigned int sdio_port_num, unsigned int on) {
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT)
sdio_port_num = CONFIG_MTK_WCN_CMB_SDIO_SLOT;
printk(KERN_WARNING "mt_combo_sdio_ctrl: force set sdio port to (%d)\n", sdio_port_num);
#endif
if ((sdio_port_num >= 4) || (combo_port_pwr_map[sdio_port_num] == 0xFF) ) {
/* invalid sdio port number or slot mapping */
printk(KERN_WARNING "mt_mtk_wcn_cmb_sdio_ctrl invalid port(%d, %d)\n", sdio_port_num, combo_port_pwr_map[sdio_port_num]);
return -1;
}
/*printk(KERN_INFO "mt_mtk_wcn_cmb_sdio_ctrl (%d, %d)\n", sdio_port_num, on);*/
if (!combo_port_pwr_map[sdio_port_num] && on) {
#if 1
printk(KERN_WARNING "board_sdio_ctrl force off before on\n");
mtk_wcn_cmb_sdio_off(sdio_port_num);
#else
printk(KERN_WARNING "skip sdio off before on\n");
#endif
combo_port_pwr_map[sdio_port_num] = 0;
/* off -> on */
mtk_wcn_cmb_sdio_on(sdio_port_num);
combo_port_pwr_map[sdio_port_num] = 1;
}
else if (combo_port_pwr_map[sdio_port_num] && !on) {
/* on -> off */
mtk_wcn_cmb_sdio_off(sdio_port_num);
combo_port_pwr_map[sdio_port_num] = 0;
}
else {
return -2;
}
return 0;
}
EXPORT_SYMBOL(board_sdio_ctrl);
int mtk_wcn_sdio_irq_flag_set (int flag)
{
if (0 != flag)
{
atomic_set(&sdio_irq_enable_flag, 1);
}
else
{
atomic_set(&sdio_irq_enable_flag, 0);
}
printk(KERN_INFO "sdio_irq_enable_flag:%d\n", atomic_read(&sdio_irq_enable_flag));
return atomic_read(&sdio_irq_enable_flag);
}
EXPORT_SYMBOL(mtk_wcn_sdio_irq_flag_set);
//#endif /* end of defined(CONFIG_MTK_COMBO) || defined(CONFIG_MTK_COMBO_MODULE) */
#endif /* end of defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) */
/*=======================================================================*/
/* Board Specific Devices Init */
/*=======================================================================*/
#if defined(CONFIG_WLAN)
int mt_wifi_resume(pm_message_t state)
{
int evt = state.event;
if (evt != PM_EVENT_USER_RESUME && evt != PM_EVENT_RESUME) {
return -1;
}
/*printk(KERN_INFO "[WIFI] %s Resume\n", evt == PM_EVENT_RESUME ? "PM":"USR");*/
return 0;
}
int mt_wifi_suspend(pm_message_t state)
{
int evt = state.event;
if (evt != PM_EVENT_USER_SUSPEND && evt != PM_EVENT_SUSPEND) {
return -1;
}
return 0;
}
void mt_wifi_power_on(void)
{
pm_message_t state = { .event = PM_EVENT_USER_RESUME };
(void)mt_wifi_resume(state);
}
EXPORT_SYMBOL(mt_wifi_power_on);
void mt_wifi_power_off(void)
{
pm_message_t state = { .event = PM_EVENT_USER_SUSPEND };
(void)mt_wifi_suspend(state);
}
EXPORT_SYMBOL(mt_wifi_power_off);
#endif /* end of defined(CONFIG_WLAN) */
/* Board Specific Devices */
/*=======================================================================*/
/*=======================================================================*/
/* Board Specific Devices Init */
/*=======================================================================*/
/*=======================================================================*/
/* Board Devices Capability */
/*=======================================================================*/
#define MSDC_SDIO_FLAG (MSDC_EXT_SDIO_IRQ | MSDC_HIGHSPEED | MSDC_UHS1)
#if defined(CFG_DEV_MSDC0)
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) && (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 0)
struct msdc_hw msdc0_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 1,
.cmd_drv = 1,
.dat_drv = 1,
.data_pins = 4,
.data_offset = 0,
//MT6630 use External IRQ, wifi uses high speed. here wifi manage his own suspend and resume, does not support hot plug
.flags = MSDC_SDIO_FLAG,//MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.cmdrtactr_sdr50 = 0x1,
.wdatcrctactr_sdr50 = 0x1,
.intdatlatcksel_sdr50 = 0x0,
.cmdrtactr_sdr200 = 0x3,
.wdatcrctactr_sdr200 = 0x3,
.intdatlatcksel_sdr200 = 0x0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SDIO,
.boot = 0,
.request_sdio_eirq = mtk_wcn_cmb_sdio_request_eirq,
.enable_sdio_eirq = mtk_wcn_cmb_sdio_enable_eirq,
.disable_sdio_eirq = mtk_wcn_cmb_sdio_disable_eirq,
.register_pm = mtk_wcn_cmb_sdio_register_pm,
};
#else
#if defined(MTK_EMMC_SUPPORT)
struct msdc_ett_settings msdc0_ett_settings[] = {
/* common ett settings */
{ MSDC_HS200_MODE, 0xb0, (0x7 << 7), 0x0 }, //PATCH_BIT0[MSDC_PB0_INT_DAT_LATCH_CK_SEL]
{ MSDC_HS200_MODE, 0xb0, (0x1f<<10), 0x0 }, //PATCH_BIT0[MSDC_PB0_CKGEN_MSDC_DLY_SEL]
{ MSDC_HS400_MODE, 0xb0, (0x7 << 7), 0x0 }, //PATCH_BIT0[MSDC_PB0_INT_DAT_LATCH_CK_SEL]
{ MSDC_HS400_MODE, 0xb0, (0x1f<<10), 0x0 }, //PATCH_BIT0[MSDC_PB0_CKGEN_MSDC_DLY_SEL]
{ MSDC_HS400_MODE, 0x188, (0x1f<< 2), 0x0 /*0x7*/ }, //EMMC50_PAD_DS_TUNE[MSDC_EMMC50_PAD_DS_TUNE_DLY1]
{ MSDC_HS400_MODE, 0x188, (0x1f<<12), 0x13 /*0x18*/}, //EMMC50_PAD_DS_TUNE[MSDC_EMMC50_PAD_DS_TUNE_DLY3]
/* command & resp ett settings */
{ MSDC_HS200_MODE, 0xb4, (0x7 << 3), 0x1 }, //PATCH_BIT1[MSDC_PB1_CMD_RSP_TA_CNTR]
{ MSDC_HS200_MODE, 0x4, (0x1 << 1), 0x1 }, //MSDC_IOCON[MSDC_IOCON_RSPL]
{ MSDC_HS200_MODE, 0xec, (0x1f<<16), 0xf }, //PAD_TUNE[MSDC_PAD_TUNE_CMDRDLY]
{ MSDC_HS200_MODE, 0xec, (0x1f<<22), 0x0 }, //PAD_TUNE[MSDC_PAD_TUNE_CMDRRDLY]
{ MSDC_HS400_MODE, 0xb4, (0x7 << 3), 0x1 }, //PATCH_BIT1[MSDC_PB1_CMD_RSP_TA_CNTR]
{ MSDC_HS400_MODE, 0x4, (0x1 << 1), 0x0 }, //MSDC_IOCON[MSDC_IOCON_RSPL]
{ MSDC_HS400_MODE, 0xec, (0x1f<<16), 0xf }, //PAD_TUNE[MSDC_PAD_TUNE_CMDRDLY]
{ MSDC_HS400_MODE, 0xec, (0x1f<<22), 0x0 /*0x3*/ }, //PAD_TUNE[MSDC_PAD_TUNE_CMDRRDLY]
/* write ett settings */
{ MSDC_HS200_MODE, 0xb4, (0x7 << 0), 0x1 }, //PATCH_BIT1[MSDC_PB1_WRDAT_CRCS_TA_CNTR]
{ MSDC_HS200_MODE, 0xec, (0x1f<< 0), 0xf }, //PAD_TUNE[MSDC_PAD_TUNE_DATWRDLY]
{ MSDC_HS200_MODE, 0x4, (0x1 <<10), 0x1 }, //MSDC_IOCON[MSDC_IOCON_W_D0SPL]
{ MSDC_HS200_MODE, 0xf0, (0x1f<<24), 0xf }, //DAT_RD_DLY0[MSDC_DAT_RDDLY0_D0]
/* read ett settings */
{ MSDC_HS200_MODE, 0xec, (0x1f<< 8), 0x16}, //PAD_TUNE[MSDC_PAD_TUNE_DATRRDLY]
{ MSDC_HS200_MODE, 0x4, (0x1 << 2), 0x0 }, //MSDC_IOCON[MSDC_IOCON_R_D_SMPL]
};
struct msdc_hw msdc0_hw = {
.clk_src = MSDC50_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 2,
.cmd_drv = 2,
.dat_drv = 2,
.rst_drv = 2,
.ds_drv = 2,
.data_pins = 8,
.data_offset = 0,
#ifndef CONFIG_MTK_EMMC_CACHE
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR | MSDC_HS400,
#else
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_CACHE | MSDC_UHS1 |MSDC_DDR | MSDC_HS400,
#endif
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.ett_count = 20, //should be same with ett_settings array size
.ett_settings = (struct msdc_ett_settings *)msdc0_ett_settings,
.host_function = MSDC_EMMC,
.boot = MSDC_BOOT_EN,
};
#else
struct msdc_hw msdc0_hw = {
.clk_src = MSDC50_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 1,
.cmd_drv = 1,
.dat_drv = 1,
.clk_drv_sd_18 = 1, /* sdr104 mode */
.cmd_drv_sd_18 = 1,
.dat_drv_sd_18 = 1,
.clk_drv_sd_18_sdr50 = 1, /* sdr50 mode */
.cmd_drv_sd_18_sdr50 = 1,
.dat_drv_sd_18_sdr50 = 1,
.clk_drv_sd_18_ddr50 = 1, /* ddr50 mode */
.cmd_drv_sd_18_ddr50 = 1,
.dat_drv_sd_18_ddr50 = 1,
.data_pins = 4,
.data_offset = 0,
//#ifdef CUST_EINT_MSDC1_INS_NUM
#if 0
.flags = MSDC_SYS_SUSPEND | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
#else
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
#endif
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SD,
.boot = 0,
.cd_level = MSDC_CD_LOW,
};
#endif
#endif
#endif
#if defined(CFG_DEV_MSDC1)
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) && (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 1)
struct msdc_hw msdc1_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 1,
.cmd_drv = 1,
.dat_drv = 1,
.data_pins = 4,
.data_offset = 0,
//MT6620 use External IRQ, wifi uses high speed. here wifi manage his own suspend and resume, does not support hot plug
.flags = MSDC_SDIO_FLAG,//MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.host_function = MSDC_SDIO,
.boot = 0,
.request_sdio_eirq = mtk_wcn_cmb_sdio_request_eirq,
.enable_sdio_eirq = mtk_wcn_cmb_sdio_enable_eirq,
.disable_sdio_eirq = mtk_wcn_cmb_sdio_disable_eirq,
.register_pm = mtk_wcn_cmb_sdio_register_pm,
};
#else
struct msdc_hw msdc1_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 3,
.cmd_drv = 3,
.dat_drv = 3,
.clk_drv_sd_18 = 3, /* sdr104 mode */
.cmd_drv_sd_18 = 2,
.dat_drv_sd_18 = 2,
.clk_drv_sd_18_sdr50 = 3, /* sdr50 mode */
.cmd_drv_sd_18_sdr50 = 2,
.dat_drv_sd_18_sdr50 = 2,
.clk_drv_sd_18_ddr50 = 3, /* ddr50 mode */
.cmd_drv_sd_18_ddr50 = 2,
.dat_drv_sd_18_ddr50 = 2,
.data_pins = 4,
.data_offset = 0,
#ifdef CUST_EINT_MSDC1_INS_NUM
.flags = MSDC_SYS_SUSPEND | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
#else
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
#endif
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SD,
.boot = 0,
.cd_level = MSDC_CD_LOW,
};
#endif
#endif
#if defined(CFG_DEV_MSDC2)
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) && (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 2)
/* MSDC2 settings for MT66xx combo connectivity chip */
struct msdc_hw msdc2_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 1,
.cmd_drv = 1,
.dat_drv = 1,
.data_pins = 4,
.data_offset = 0,
//MT6620 use External IRQ, wifi uses high speed. here wifi manage his own suspend and resume, does not support hot plug
.flags = MSDC_SDIO_FLAG,//MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.host_function = MSDC_SDIO,
.boot = 0,
.request_sdio_eirq = mtk_wcn_cmb_sdio_request_eirq,
.enable_sdio_eirq = mtk_wcn_cmb_sdio_enable_eirq,
.disable_sdio_eirq = mtk_wcn_cmb_sdio_disable_eirq,
.register_pm = mtk_wcn_cmb_sdio_register_pm,
};
#else
struct msdc_hw msdc2_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 3,
.cmd_drv = 3,
.dat_drv = 3,
.clk_drv_sd_18 = 3, /* sdr104 mode */
.cmd_drv_sd_18 = 2,
.dat_drv_sd_18 = 2,
.clk_drv_sd_18_sdr50 = 3, /* sdr50 mode */
.cmd_drv_sd_18_sdr50 = 2,
.dat_drv_sd_18_sdr50 = 2,
.clk_drv_sd_18_ddr50 = 3, /* ddr50 mode */
.cmd_drv_sd_18_ddr50 = 2,
.dat_drv_sd_18_ddr50 = 2,
.data_pins = 4,
.data_offset = 0,
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SD,
.boot = 0,
.cd_level = MSDC_CD_LOW,
};
#endif
#endif
#if defined(CFG_DEV_MSDC3)
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) && (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 3)
/* MSDC3 settings for MT66xx combo connectivity chip */
struct msdc_hw msdc3_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 4,
.cmd_drv = 4,
.dat_drv = 4,
.clk_drv_sd_18 = 4,
.cmd_drv_sd_18 = 4,
.dat_drv_sd_18 = 4,
.data_pins = 4,
.data_offset = 0,
//MT6620 use External IRQ, wifi uses high speed. here wifi manage his own suspend and resume, does not support hot plug
.flags = MSDC_SDIO_FLAG | MSDC_UHS1,//MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.cmdrtactr_sdr50 = 0x3,
.wdatcrctactr_sdr50 = 0x1,
.intdatlatcksel_sdr50 = 0x0,
.cmdrtactr_sdr200 = 0x4,
.wdatcrctactr_sdr200 = 0x2,
.intdatlatcksel_sdr200 = 0x0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SDIO,
.boot = 0,
.request_sdio_eirq = mtk_wcn_cmb_sdio_request_eirq,
.enable_sdio_eirq = mtk_wcn_cmb_sdio_enable_eirq,
.disable_sdio_eirq = mtk_wcn_cmb_sdio_disable_eirq,
.register_pm = mtk_wcn_cmb_sdio_register_pm,
};
#else
struct msdc_hw msdc3_hw;
#endif
#endif
/* MT6575 NAND Driver */
#if defined(CONFIG_MTK_MTD_NAND)
struct mt6575_nand_host_hw mt6575_nand_hw = {
.nfi_bus_width = 8,
.nfi_access_timing = NFI_DEFAULT_ACCESS_TIMING,
.nfi_cs_num = NFI_CS_NUM,
.nand_sec_size = 512,
.nand_sec_shift = 9,
.nand_ecc_size = 2048,
.nand_ecc_bytes = 32,
.nand_ecc_mode = NAND_ECC_HW,
};
#endif
一 根据原理图配置好GPIO
二 修改代码,有如下几只文件需要修改:
1 alps/mediatek/config/{project}/ProjectConfig.mk添加如下option:
CUSTOM_HAL_COMBO=mt6630
CUSTOM_HAL_ANT=mt6630_ant_m1
MTK_COMBO_CORE_DUMP_SUPPORT=no
MTK_COMBO_QUICK_SLEEP_SUPPORT=no
MTK_COMBO_CHIP = MT6630
MTK_WLAN_CHIP=MT6630
MTK_BT_CHIP = MTK_MT6630
MTK_GPS_CHIP = MTK_GPS_MT6630
MTK_FM_CHIP=MT6630_FM
(注意:最好double check原ProjectConfig文件是否已经存在某项option,如果存在且取值一样,则不需要添加;如果只是值不同,则修改为上述值)
2 alps/mediatek/config/{project}/init.project.rc factory_init.project.rc meta_init.project.rc这三只文件
统一作如下2处修改:
service conn_launcher /system/bin/logwrapper /system/bin/6620_launcher -p /system/etc/firmware/
改为:
service 66xx_launcher /system/bin/logwrapper /system/bin/6620_launcher -m 4 -p /system/etc/firmware/
在文件末尾添加:
service autokd /system/bin/autokd
class core
user system
group nvram system
3 alps\mediatek\config\{project}\autoconfig\kconfig\project文件末尾添加:
CONFIG_SDIOAUTOK_SUPPORT=y
4 alps\mediatek\custom\{project}\kernel\core\src\board-custom.h文件作如下3处改动:
//#define CFG_DEV_MSDC3
改为:
#define CFG_DEV_MSDC3
#define CONFIG_MTK_COMBO_SDIO_SLOT (3)
改为:
#define CONFIG_MTK_WCN_CMB_SDIO_SLOT (3)
#undef CONFIG_MTK_COMBO_SDIO_SLOT
改为:
#undef CONFIG_MTK_WCN_CMB_SDIO_SLOT
5 alps\mediatek\custom\{project}\kernel\core\src\board.c文件,因改动内容较多,
最好整个将文件替换为如下内容:
/* system header files */
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include <linux/mtd/nand.h>
#include <asm/irq.h>
#include <asm/io.h>
//#include <asm/mach-types.h>
//#include <asm/mach/arch.h>
//#include <asm/mach/irq.h>
//#include <asm/mach/map.h>
//#include <asm/mach/time.h>
//#include <asm/setup.h>
#include <mach/system.h>
#include <mach/board.h>
#include <mach/hardware.h>
#include <mach/mt_gpio.h>
#include <mach/mt_bt.h>
#include <mach/eint.h>
#include <mach/mtk_rtc.h>
#include <mach/mt_typedefs.h>
// Fix-me: marked for early porting
#include <cust_gpio_usage.h>
#include <cust_eint.h>
#define CONFIG_EINT_DEVICE_TREE 0
#if CONFIG_EINT_DEVICE_TREE
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/irqreturn.h>
static atomic_t wifi_irq_flag;
static unsigned int wifi_irq = 0;
#endif
#include "board-custom.h"
#if defined(CONFIG_MTK_COMBO) || defined(CONFIG_MTK_COMBO_MODULE)
#include <mach/mtk_wcn_cmb_stub.h>
#endif
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT)
static sdio_irq_handler_t mtk_wcn_cmb_sdio_eirq_handler = NULL;
int mtk_wcn_sdio_irq_flag_set (int falg);
static atomic_t sdio_irq_enable_flag;
static pm_callback_t mtk_wcn_cmb_sdio_pm_cb = NULL;
static void *mtk_wcn_cmb_sdio_pm_data = http://www.mamicode.com/NULL;
static void *mtk_wcn_cmb_sdio_eirq_data = http://www.mamicode.com/NULL;
const static u32 mtk_wcn_cmb_sdio_eint_pin = GPIO_WIFI_EINT_PIN;
const static u32 mtk_wcn_cmb_sdio_eint_num = CUST_EINT_WIFI_NUM;
const static u32 mtk_wcn_cmb_sdio_eint_m_eint = GPIO_WIFI_EINT_PIN_M_EINT;
const static u32 mtk_wcn_cmb_sdio_eint_m_gpio = GPIO_WIFI_EINT_PIN_M_GPIO;
/*
index: port number of combo chip (1:SDIO1, 2:SDIO2, no SDIO0)
value: slot power status of (0:off, 1:on, 0xFF:invalid)
*/
#if (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 0)
static unsigned char combo_port_pwr_map[4] = {0x0, 0xFF, 0xFF, 0xFF};
#elif (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 1)
static unsigned char combo_port_pwr_map[4] = {0xFF, 0x0, 0xFF, 0xFF};
#elif (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 2)
static unsigned char combo_port_pwr_map[4] = {0xFF, 0xFF, 0x0, 0xFF};
#elif (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 3)
static unsigned char combo_port_pwr_map[4] = {0xFF, 0xFF, 0xFF, 0x0};
#else
#error "unsupported CONFIG_MTK_WCN_CMB_SDIO_SLOT" CONFIG_MTK_WCN_CMB_SDIO_SLOT
#endif
#else
/*standalone chip‘s structure should be add here*/
#endif
/*=======================================================================*/
/* Board Specific Devices Power Management */
/*=======================================================================*/
extern kal_bool pmic_chrdet_status(void);
void mt_power_off(void)
{
printk("mt_power_off\n");
/* pull PWRBB low */
/*Hong-Rong: FIXME for early porting*/
rtc_bbpu_power_down();
while (1) {
#if defined(CONFIG_POWER_EXT)
//EVB
printk("EVB without charger\n");
#else
//Phone
printk("Phone with charger\n");
if (pmic_chrdet_status() == KAL_TRUE)
arch_reset(0, "power_off_with_charger");
#endif
}
}
/*=======================================================================*/
/* Board Specific Devices */
/*=======================================================================*/
/*GPS driver*/
/*FIXME: remove mt3326 notation */
struct mt3326_gps_hardware mt3326_gps_hw = {
.ext_power_on = NULL,
.ext_power_off = NULL,
};
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT)
static void mtk_wcn_cmb_sdio_enable_eirq(void)
{
#if CONFIG_EINT_DEVICE_TREE
if(!atomic_read(&wifi_irq_flag))
{
printk(KERN_DEBUG "wifi eint has been enabled\n");;
}
else
{
enable_irq(wifi_irq);
atomic_dec(&wifi_irq_flag);
//printk(KERN_DEBUG " enable WIFI EINT irq %d !!\n",wifi_irq);
}
#else
mt_eint_unmask(mtk_wcn_cmb_sdio_eint_num);/* CUST_EINT_WIFI_NUM */
#endif
}
static void mtk_wcn_cmb_sdio_disable_eirq(void)
{
#if CONFIG_EINT_DEVICE_TREE
if(atomic_read(&wifi_irq_flag))
{
printk(KERN_DEBUG "wifi eint has been disabled!\n");;
}
else
{
disable_irq_nosync(wifi_irq);
atomic_inc(&wifi_irq_flag);
//printk(KERN_DEBUG "disable WIFI EINT irq %d !!\n",wifi_irq);
}
#else
mt_eint_mask(mtk_wcn_cmb_sdio_eint_num); /* CUST_EINT_WIFI_NUM */
#endif
}
#if CONFIG_EINT_DEVICE_TREE
irqreturn_t mtk_wcn_cmb_sdio_eirq_handler_stub(int irq,void *data)
{
if ((NULL != mtk_wcn_cmb_sdio_eirq_handler) && (0 != atomic_read(&sdio_irq_enable_flag))) {
mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data);
}
return IRQ_HANDLED;
}
#else
static void mtk_wcn_cmb_sdio_eirq_handler_stub(void)
{
if ((NULL != mtk_wcn_cmb_sdio_eirq_handler) && (0 != atomic_read(&sdio_irq_enable_flag))) {
mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data);
}
}
#endif
static void mtk_wcn_cmb_sdio_request_eirq(sdio_irq_handler_t irq_handler, void *data)
{
#if CONFIG_EINT_DEVICE_TREE
struct device_node *node;
u32 ints[2] = {0,0};
int ret = -EINVAL;
#endif
printk( KERN_INFO "enter %s\n", __func__);
mtk_wcn_sdio_irq_flag_set (0);
mtk_wcn_cmb_sdio_eirq_data = data;
mtk_wcn_cmb_sdio_eirq_handler = irq_handler;
#if 1
#if CONFIG_EINT_DEVICE_TREE
node = of_find_compatible_node(NULL, NULL, "mediatek, WIFI-eint");
if(node) {
of_property_read_u32_array(node, "debounce", ints, ARRAY_SIZE(ints));
mt_gpio_set_debounce(ints[0], ints[1]);
wifi_irq = irq_of_parse_and_map(node, 0);
ret = request_irq(wifi_irq, mtk_wcn_cmb_sdio_eirq_handler_stub, IRQF_TRIGGER_NONE,"WIFI-eint", NULL);
printk(KERN_DEBUG "WIFI EINT irq %d !!\n",wifi_irq);
atomic_set(&wifi_irq_flag, 0);/*default: irq enable*/
if(ret)
printk(KERN_ERR "WIFI EINT IRQ LINE NOT AVAILABLE!!\n");
else {
mtk_wcn_cmb_sdio_disable_eirq();/*not ,chip state is power off*/
}
}
else
printk(KERN_ERR "[%s] can‘t find wifi eint compatible node\n",__func__);
#else
mt_eint_registration(mtk_wcn_cmb_sdio_eint_num,
CUST_EINT_WIFI_TYPE,
mtk_wcn_cmb_sdio_eirq_handler_stub,
0);
#endif
#else
{
int i_ret = 0;
i_ret = request_irq(mtk_wcn_cmb_sdio_eint_num,
(irq_handler_t)mtk_wcn_cmb_sdio_eirq_handler_stub,
IRQF_TRIGGER_LOW,
"SDIO_EXT_IRQ",
NULL);
if (i_ret)
printk( KERN_ERR "request_irq for SDIO ext IRQ failed, i_ret(%d)\n", i_ret);
else
printk( KERN_ERR "request_irq for SDIO ext IRQ succeed, i_ret(%d)\n", i_ret);
}
#endif
#if CONFIG_EINT_DEVICE_TREE
#else
mt_eint_mask(mtk_wcn_cmb_sdio_eint_num);/*CUST_EINT_WIFI_NUM */
#endif
printk(KERN_INFO "exit %s\n", __func__);
}
static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data)
{
printk( KERN_INFO "mtk_wcn_cmb_sdio_register_pm (0x%p, 0x%p)\n", pm_cb, data);
/* register pm change callback */
mtk_wcn_cmb_sdio_pm_cb = pm_cb;
mtk_wcn_cmb_sdio_pm_data = http://www.mamicode.com/data;
}
static void mtk_wcn_cmb_sdio_on (int sdio_port_num) {
pm_message_t state = { .event = PM_EVENT_USER_RESUME };
printk(KERN_INFO "mtk_wcn_cmb_sdio_on (%d) \n", sdio_port_num);
/* 1. disable sdio eirq */
mtk_wcn_cmb_sdio_disable_eirq();
mt_set_gpio_pull_enable(mtk_wcn_cmb_sdio_eint_pin, GPIO_PULL_DISABLE); /* GPIO_WIFI_EINT_PIN */
mt_set_gpio_mode(mtk_wcn_cmb_sdio_eint_pin, mtk_wcn_cmb_sdio_eint_m_eint); /* EINT mode */
/* 2. call sd callback */
if (mtk_wcn_cmb_sdio_pm_cb) {
//printk(KERN_INFO "mtk_wcn_cmb_sdio_pm_cb(PM_EVENT_USER_RESUME, 0x%p, 0x%p) \n", mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data);
mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data);
}
else {
printk(KERN_WARNING "mtk_wcn_cmb_sdio_on no sd callback!!\n");
}
}
static void mtk_wcn_cmb_sdio_off (int sdio_port_num) {
pm_message_t state = { .event = PM_EVENT_USER_SUSPEND };
printk(KERN_INFO "mtk_wcn_cmb_sdio_off (%d) \n", sdio_port_num);
/* 1. call sd callback */
if (mtk_wcn_cmb_sdio_pm_cb) {
//printk(KERN_INFO "mtk_wcn_cmb_sdio_off(PM_EVENT_USER_SUSPEND, 0x%p, 0x%p) \n", mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data);
mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data);
}
else {
printk(KERN_WARNING "mtk_wcn_cmb_sdio_off no sd callback!!\n");
}
/* 2. disable sdio eirq */
mtk_wcn_cmb_sdio_disable_eirq();
/*printk(KERN_INFO "[mt6620] set WIFI_EINT input pull down\n");*/
mt_set_gpio_mode(mtk_wcn_cmb_sdio_eint_pin, mtk_wcn_cmb_sdio_eint_m_gpio); /* GPIO mode */
mt_set_gpio_dir(mtk_wcn_cmb_sdio_eint_pin, GPIO_DIR_IN);
mt_set_gpio_pull_select(mtk_wcn_cmb_sdio_eint_pin, GPIO_PULL_UP);
mt_set_gpio_pull_enable(mtk_wcn_cmb_sdio_eint_pin, GPIO_PULL_ENABLE);
}
int board_sdio_ctrl (unsigned int sdio_port_num, unsigned int on) {
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT)
sdio_port_num = CONFIG_MTK_WCN_CMB_SDIO_SLOT;
printk(KERN_WARNING "mt_combo_sdio_ctrl: force set sdio port to (%d)\n", sdio_port_num);
#endif
if ((sdio_port_num >= 4) || (combo_port_pwr_map[sdio_port_num] == 0xFF) ) {
/* invalid sdio port number or slot mapping */
printk(KERN_WARNING "mt_mtk_wcn_cmb_sdio_ctrl invalid port(%d, %d)\n", sdio_port_num, combo_port_pwr_map[sdio_port_num]);
return -1;
}
/*printk(KERN_INFO "mt_mtk_wcn_cmb_sdio_ctrl (%d, %d)\n", sdio_port_num, on);*/
if (!combo_port_pwr_map[sdio_port_num] && on) {
#if 1
printk(KERN_WARNING "board_sdio_ctrl force off before on\n");
mtk_wcn_cmb_sdio_off(sdio_port_num);
#else
printk(KERN_WARNING "skip sdio off before on\n");
#endif
combo_port_pwr_map[sdio_port_num] = 0;
/* off -> on */
mtk_wcn_cmb_sdio_on(sdio_port_num);
combo_port_pwr_map[sdio_port_num] = 1;
}
else if (combo_port_pwr_map[sdio_port_num] && !on) {
/* on -> off */
mtk_wcn_cmb_sdio_off(sdio_port_num);
combo_port_pwr_map[sdio_port_num] = 0;
}
else {
return -2;
}
return 0;
}
EXPORT_SYMBOL(board_sdio_ctrl);
int mtk_wcn_sdio_irq_flag_set (int flag)
{
if (0 != flag)
{
atomic_set(&sdio_irq_enable_flag, 1);
}
else
{
atomic_set(&sdio_irq_enable_flag, 0);
}
printk(KERN_INFO "sdio_irq_enable_flag:%d\n", atomic_read(&sdio_irq_enable_flag));
return atomic_read(&sdio_irq_enable_flag);
}
EXPORT_SYMBOL(mtk_wcn_sdio_irq_flag_set);
//#endif /* end of defined(CONFIG_MTK_COMBO) || defined(CONFIG_MTK_COMBO_MODULE) */
#endif /* end of defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) */
/*=======================================================================*/
/* Board Specific Devices Init */
/*=======================================================================*/
#if defined(CONFIG_WLAN)
int mt_wifi_resume(pm_message_t state)
{
int evt = state.event;
if (evt != PM_EVENT_USER_RESUME && evt != PM_EVENT_RESUME) {
return -1;
}
/*printk(KERN_INFO "[WIFI] %s Resume\n", evt == PM_EVENT_RESUME ? "PM":"USR");*/
return 0;
}
int mt_wifi_suspend(pm_message_t state)
{
int evt = state.event;
if (evt != PM_EVENT_USER_SUSPEND && evt != PM_EVENT_SUSPEND) {
return -1;
}
return 0;
}
void mt_wifi_power_on(void)
{
pm_message_t state = { .event = PM_EVENT_USER_RESUME };
(void)mt_wifi_resume(state);
}
EXPORT_SYMBOL(mt_wifi_power_on);
void mt_wifi_power_off(void)
{
pm_message_t state = { .event = PM_EVENT_USER_SUSPEND };
(void)mt_wifi_suspend(state);
}
EXPORT_SYMBOL(mt_wifi_power_off);
#endif /* end of defined(CONFIG_WLAN) */
/* Board Specific Devices */
/*=======================================================================*/
/*=======================================================================*/
/* Board Specific Devices Init */
/*=======================================================================*/
/*=======================================================================*/
/* Board Devices Capability */
/*=======================================================================*/
#define MSDC_SDIO_FLAG (MSDC_EXT_SDIO_IRQ | MSDC_HIGHSPEED | MSDC_UHS1)
#if defined(CFG_DEV_MSDC0)
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) && (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 0)
struct msdc_hw msdc0_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 1,
.cmd_drv = 1,
.dat_drv = 1,
.data_pins = 4,
.data_offset = 0,
//MT6630 use External IRQ, wifi uses high speed. here wifi manage his own suspend and resume, does not support hot plug
.flags = MSDC_SDIO_FLAG,//MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.cmdrtactr_sdr50 = 0x1,
.wdatcrctactr_sdr50 = 0x1,
.intdatlatcksel_sdr50 = 0x0,
.cmdrtactr_sdr200 = 0x3,
.wdatcrctactr_sdr200 = 0x3,
.intdatlatcksel_sdr200 = 0x0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SDIO,
.boot = 0,
.request_sdio_eirq = mtk_wcn_cmb_sdio_request_eirq,
.enable_sdio_eirq = mtk_wcn_cmb_sdio_enable_eirq,
.disable_sdio_eirq = mtk_wcn_cmb_sdio_disable_eirq,
.register_pm = mtk_wcn_cmb_sdio_register_pm,
};
#else
#if defined(MTK_EMMC_SUPPORT)
struct msdc_ett_settings msdc0_ett_settings[] = {
/* common ett settings */
{ MSDC_HS200_MODE, 0xb0, (0x7 << 7), 0x0 }, //PATCH_BIT0[MSDC_PB0_INT_DAT_LATCH_CK_SEL]
{ MSDC_HS200_MODE, 0xb0, (0x1f<<10), 0x0 }, //PATCH_BIT0[MSDC_PB0_CKGEN_MSDC_DLY_SEL]
{ MSDC_HS400_MODE, 0xb0, (0x7 << 7), 0x0 }, //PATCH_BIT0[MSDC_PB0_INT_DAT_LATCH_CK_SEL]
{ MSDC_HS400_MODE, 0xb0, (0x1f<<10), 0x0 }, //PATCH_BIT0[MSDC_PB0_CKGEN_MSDC_DLY_SEL]
{ MSDC_HS400_MODE, 0x188, (0x1f<< 2), 0x0 /*0x7*/ }, //EMMC50_PAD_DS_TUNE[MSDC_EMMC50_PAD_DS_TUNE_DLY1]
{ MSDC_HS400_MODE, 0x188, (0x1f<<12), 0x13 /*0x18*/}, //EMMC50_PAD_DS_TUNE[MSDC_EMMC50_PAD_DS_TUNE_DLY3]
/* command & resp ett settings */
{ MSDC_HS200_MODE, 0xb4, (0x7 << 3), 0x1 }, //PATCH_BIT1[MSDC_PB1_CMD_RSP_TA_CNTR]
{ MSDC_HS200_MODE, 0x4, (0x1 << 1), 0x1 }, //MSDC_IOCON[MSDC_IOCON_RSPL]
{ MSDC_HS200_MODE, 0xec, (0x1f<<16), 0xf }, //PAD_TUNE[MSDC_PAD_TUNE_CMDRDLY]
{ MSDC_HS200_MODE, 0xec, (0x1f<<22), 0x0 }, //PAD_TUNE[MSDC_PAD_TUNE_CMDRRDLY]
{ MSDC_HS400_MODE, 0xb4, (0x7 << 3), 0x1 }, //PATCH_BIT1[MSDC_PB1_CMD_RSP_TA_CNTR]
{ MSDC_HS400_MODE, 0x4, (0x1 << 1), 0x0 }, //MSDC_IOCON[MSDC_IOCON_RSPL]
{ MSDC_HS400_MODE, 0xec, (0x1f<<16), 0xf }, //PAD_TUNE[MSDC_PAD_TUNE_CMDRDLY]
{ MSDC_HS400_MODE, 0xec, (0x1f<<22), 0x0 /*0x3*/ }, //PAD_TUNE[MSDC_PAD_TUNE_CMDRRDLY]
/* write ett settings */
{ MSDC_HS200_MODE, 0xb4, (0x7 << 0), 0x1 }, //PATCH_BIT1[MSDC_PB1_WRDAT_CRCS_TA_CNTR]
{ MSDC_HS200_MODE, 0xec, (0x1f<< 0), 0xf }, //PAD_TUNE[MSDC_PAD_TUNE_DATWRDLY]
{ MSDC_HS200_MODE, 0x4, (0x1 <<10), 0x1 }, //MSDC_IOCON[MSDC_IOCON_W_D0SPL]
{ MSDC_HS200_MODE, 0xf0, (0x1f<<24), 0xf }, //DAT_RD_DLY0[MSDC_DAT_RDDLY0_D0]
/* read ett settings */
{ MSDC_HS200_MODE, 0xec, (0x1f<< 8), 0x16}, //PAD_TUNE[MSDC_PAD_TUNE_DATRRDLY]
{ MSDC_HS200_MODE, 0x4, (0x1 << 2), 0x0 }, //MSDC_IOCON[MSDC_IOCON_R_D_SMPL]
};
struct msdc_hw msdc0_hw = {
.clk_src = MSDC50_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 2,
.cmd_drv = 2,
.dat_drv = 2,
.rst_drv = 2,
.ds_drv = 2,
.data_pins = 8,
.data_offset = 0,
#ifndef CONFIG_MTK_EMMC_CACHE
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR | MSDC_HS400,
#else
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_CACHE | MSDC_UHS1 |MSDC_DDR | MSDC_HS400,
#endif
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.ett_count = 20, //should be same with ett_settings array size
.ett_settings = (struct msdc_ett_settings *)msdc0_ett_settings,
.host_function = MSDC_EMMC,
.boot = MSDC_BOOT_EN,
};
#else
struct msdc_hw msdc0_hw = {
.clk_src = MSDC50_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 1,
.cmd_drv = 1,
.dat_drv = 1,
.clk_drv_sd_18 = 1, /* sdr104 mode */
.cmd_drv_sd_18 = 1,
.dat_drv_sd_18 = 1,
.clk_drv_sd_18_sdr50 = 1, /* sdr50 mode */
.cmd_drv_sd_18_sdr50 = 1,
.dat_drv_sd_18_sdr50 = 1,
.clk_drv_sd_18_ddr50 = 1, /* ddr50 mode */
.cmd_drv_sd_18_ddr50 = 1,
.dat_drv_sd_18_ddr50 = 1,
.data_pins = 4,
.data_offset = 0,
//#ifdef CUST_EINT_MSDC1_INS_NUM
#if 0
.flags = MSDC_SYS_SUSPEND | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
#else
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
#endif
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SD,
.boot = 0,
.cd_level = MSDC_CD_LOW,
};
#endif
#endif
#endif
#if defined(CFG_DEV_MSDC1)
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) && (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 1)
struct msdc_hw msdc1_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 1,
.cmd_drv = 1,
.dat_drv = 1,
.data_pins = 4,
.data_offset = 0,
//MT6620 use External IRQ, wifi uses high speed. here wifi manage his own suspend and resume, does not support hot plug
.flags = MSDC_SDIO_FLAG,//MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.host_function = MSDC_SDIO,
.boot = 0,
.request_sdio_eirq = mtk_wcn_cmb_sdio_request_eirq,
.enable_sdio_eirq = mtk_wcn_cmb_sdio_enable_eirq,
.disable_sdio_eirq = mtk_wcn_cmb_sdio_disable_eirq,
.register_pm = mtk_wcn_cmb_sdio_register_pm,
};
#else
struct msdc_hw msdc1_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 3,
.cmd_drv = 3,
.dat_drv = 3,
.clk_drv_sd_18 = 3, /* sdr104 mode */
.cmd_drv_sd_18 = 2,
.dat_drv_sd_18 = 2,
.clk_drv_sd_18_sdr50 = 3, /* sdr50 mode */
.cmd_drv_sd_18_sdr50 = 2,
.dat_drv_sd_18_sdr50 = 2,
.clk_drv_sd_18_ddr50 = 3, /* ddr50 mode */
.cmd_drv_sd_18_ddr50 = 2,
.dat_drv_sd_18_ddr50 = 2,
.data_pins = 4,
.data_offset = 0,
#ifdef CUST_EINT_MSDC1_INS_NUM
.flags = MSDC_SYS_SUSPEND | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
#else
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
#endif
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SD,
.boot = 0,
.cd_level = MSDC_CD_LOW,
};
#endif
#endif
#if defined(CFG_DEV_MSDC2)
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) && (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 2)
/* MSDC2 settings for MT66xx combo connectivity chip */
struct msdc_hw msdc2_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 1,
.cmd_drv = 1,
.dat_drv = 1,
.data_pins = 4,
.data_offset = 0,
//MT6620 use External IRQ, wifi uses high speed. here wifi manage his own suspend and resume, does not support hot plug
.flags = MSDC_SDIO_FLAG,//MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.host_function = MSDC_SDIO,
.boot = 0,
.request_sdio_eirq = mtk_wcn_cmb_sdio_request_eirq,
.enable_sdio_eirq = mtk_wcn_cmb_sdio_enable_eirq,
.disable_sdio_eirq = mtk_wcn_cmb_sdio_disable_eirq,
.register_pm = mtk_wcn_cmb_sdio_register_pm,
};
#else
struct msdc_hw msdc2_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 3,
.cmd_drv = 3,
.dat_drv = 3,
.clk_drv_sd_18 = 3, /* sdr104 mode */
.cmd_drv_sd_18 = 2,
.dat_drv_sd_18 = 2,
.clk_drv_sd_18_sdr50 = 3, /* sdr50 mode */
.cmd_drv_sd_18_sdr50 = 2,
.dat_drv_sd_18_sdr50 = 2,
.clk_drv_sd_18_ddr50 = 3, /* ddr50 mode */
.cmd_drv_sd_18_ddr50 = 2,
.dat_drv_sd_18_ddr50 = 2,
.data_pins = 4,
.data_offset = 0,
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED | MSDC_UHS1 |MSDC_DDR,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SD,
.boot = 0,
.cd_level = MSDC_CD_LOW,
};
#endif
#endif
#if defined(CFG_DEV_MSDC3)
#if defined(CONFIG_MTK_WCN_CMB_SDIO_SLOT) && (CONFIG_MTK_WCN_CMB_SDIO_SLOT == 3)
/* MSDC3 settings for MT66xx combo connectivity chip */
struct msdc_hw msdc3_hw = {
.clk_src = MSDC30_CLKSRC_200MHZ,
.cmd_edge = MSDC_SMPL_FALLING,
.rdata_edge = MSDC_SMPL_FALLING,
.wdata_edge = MSDC_SMPL_FALLING,
.clk_drv = 4,
.cmd_drv = 4,
.dat_drv = 4,
.clk_drv_sd_18 = 4,
.cmd_drv_sd_18 = 4,
.dat_drv_sd_18 = 4,
.data_pins = 4,
.data_offset = 0,
//MT6620 use External IRQ, wifi uses high speed. here wifi manage his own suspend and resume, does not support hot plug
.flags = MSDC_SDIO_FLAG | MSDC_UHS1,//MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE,
.dat0rddly = 0,
.dat1rddly = 0,
.dat2rddly = 0,
.dat3rddly = 0,
.dat4rddly = 0,
.dat5rddly = 0,
.dat6rddly = 0,
.dat7rddly = 0,
.datwrddly = 0,
.cmdrrddly = 0,
.cmdrddly = 0,
.cmdrtactr_sdr50 = 0x3,
.wdatcrctactr_sdr50 = 0x1,
.intdatlatcksel_sdr50 = 0x0,
.cmdrtactr_sdr200 = 0x4,
.wdatcrctactr_sdr200 = 0x2,
.intdatlatcksel_sdr200 = 0x0,
.ett_count = 0, //should be same with ett_settings array size
.host_function = MSDC_SDIO,
.boot = 0,
.request_sdio_eirq = mtk_wcn_cmb_sdio_request_eirq,
.enable_sdio_eirq = mtk_wcn_cmb_sdio_enable_eirq,
.disable_sdio_eirq = mtk_wcn_cmb_sdio_disable_eirq,
.register_pm = mtk_wcn_cmb_sdio_register_pm,
};
#else
struct msdc_hw msdc3_hw;
#endif
#endif
/* MT6575 NAND Driver */
#if defined(CONFIG_MTK_MTD_NAND)
struct mt6575_nand_host_hw mt6575_nand_hw = {
.nfi_bus_width = 8,
.nfi_access_timing = NFI_DEFAULT_ACCESS_TIMING,
.nfi_cs_num = NFI_CS_NUM,
.nand_sec_size = 512,
.nand_sec_shift = 9,
.nand_ecc_size = 2048,
.nand_ecc_bytes = 32,
.nand_ecc_mode = NAND_ECC_HW,
};
#endif
MTK 6752/6732支持6630
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。