/*++ linux/arch/arm/mach-wmt/generic.c wmt generic architecture level codes Copyright (c) 2013 WonderMedia Technologies, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . WonderMedia Technologies, Inc. 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. --*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "generic.h" #include #ifdef CONFIG_WMT_NEWSPI_SUPPORT #include #endif #ifdef CONFIG_WMT_NEWSPI1_SUPPORT #include #endif #include #include extern void enable_user_access(void); /* TODO*/ #define PMHC_HIBERNATE 0x205 extern void __init wmt_gpio_init(void); extern void wmt_power_up_debounce_value(void); extern void wmt_restart(char mode, const char *cmd); extern void (*arm_pm_restart)(char str, const char *cmd); static void wmt_power_off(void) { #ifdef CONFIG_PM /*set power button debounce value*/ wmt_power_up_debounce_value(); #endif mdelay(100); local_irq_disable(); *(volatile unsigned int *)0xfe018008 |= 0x03030303; //scu output pm #ifndef CONFIG_SMP PMCEU_VAL |= 0x00800000;//sf boot, enable sf for single core pm mdelay(1); #endif /* * Set scratchpad to zero, just in case it is used as a restart * address by the bootloader. Since PB_RESUME button has been * set to be one of the wakeup sources, clean the resume address * will cause zacboot to issue a SW_RESET, for design a behavior * to let PB_RESUME button be a power on button. * * Also force to disable watchdog timer, if it has been enabled. */ HSP0_VAL = 0; OSTW_VAL &= ~OSTW_WE; /* * Well, I cannot power-off myself, * so try to enter power-off suspend mode. */ //for single core #ifndef CONFIG_SMP HSP7_VAL = 0xffffffb8; while(HSP7_VAL != 0xffffffb8); asm("sev" : : "r" (0)); #endif //PMWTC_VAL = 0x2000;//DCDET falling *(unsigned char *)0xfe13005c = 0x0; #if 0 PMWT_VAL = 0x40000000; mdelay(1); PMWS_VAL = PMWS_VAL; mdelay(1); PMWE_VAL = 0x00004080;//DCDET + PWRBTN mdelay(1); WK_TRG_EN_VAL = 0x00004080;//DCDET + PWRBTN if (DCDET_STS_VAL & 0x100) PMHC_VAL = PMHC_SUSPEND; //#else if (DCDET_STS_VAL & 0x100) PMSR_VAL = PMSR_SWR; else #endif PMHC_VAL = PMHC_HIBERNATE; //asm("mcr%? p15, 0, %0, c7, c0, 4" : : "r" (0)); /* Force ARM to idle mode*/ do { asm("wfi" : : "r" (0)); /* Force ARM to idle mode*/ } while(1); } static struct resource wmt_uart0_resources[] = { [0] = { .start = UART0_BASE_ADDR, .end = (UART0_BASE_ADDR + 0xFFFF), .flags = IORESOURCE_MEM, }, }; static struct resource wmt_uart1_resources[] = { [0] = { .start = UART1_BASE_ADDR, .end = (UART1_BASE_ADDR + 0xFFFF), .flags = IORESOURCE_MEM, }, }; #ifdef CONFIG_UART_2_3_ENABLE static struct resource wmt_uart2_resources[] = { [0] = { .start = UART2_BASE_ADDR, .end = (UART2_BASE_ADDR + 0xFFFF), .flags = IORESOURCE_MEM, }, }; static struct resource wmt_uart3_resources[] = { [0] = { .start = UART3_BASE_ADDR, .end = (UART3_BASE_ADDR + 0xFFFF), .flags = IORESOURCE_MEM, }, }; #endif static struct platform_device wmt_uart0_device = { .name = "uart", .id = 0, .num_resources = ARRAY_SIZE(wmt_uart0_resources), .resource = wmt_uart0_resources, }; static struct platform_device wmt_uart1_device = { .name = "uart", .id = 1, .num_resources = ARRAY_SIZE(wmt_uart1_resources), .resource = wmt_uart1_resources, }; #ifdef CONFIG_UART_2_3_ENABLE static struct platform_device wmt_uart2_device = { .name = "uart", .id = 2, .num_resources = ARRAY_SIZE(wmt_uart2_resources), .resource = wmt_uart2_resources, }; static struct platform_device wmt_uart3_device = { .name = "uart", .id = 3, .num_resources = ARRAY_SIZE(wmt_uart3_resources), .resource = wmt_uart3_resources, }; #endif static struct resource wmt_sf_resources[] = { [0] = { .start = SF_MEM_CTRL_CFG_BASE_ADDR, .end = SF_MEM_CTRL_CFG_BASE_ADDR + 0x3FF, .flags = IORESOURCE_MEM, }, }; static struct platform_device wmt_sf_device = { .name = "sf", .id = 0, .num_resources = ARRAY_SIZE(wmt_sf_resources), .resource = wmt_sf_resources, }; #ifdef CONFIG_MTD_WMT_NOR static struct resource wmt_nor_resources[] = { [0] = { .start = NOR_CTRL_CFG_BASE_ADDR, .end = NOR_CTRL_CFG_BASE_ADDR + 0x3FF, .flags = IORESOURCE_MEM, }, }; static struct platform_device wmt_nor_device = { .name = "nor", .id = 0, .num_resources = ARRAY_SIZE(wmt_nor_resources), .resource = wmt_nor_resources, }; #endif static struct resource wmt_nand_resources[] = { [0] = { .start = NF_CTRL_CFG_BASE_ADDR, .end = NF_CTRL_CFG_BASE_ADDR + 0x3FF, .flags = IORESOURCE_MEM, }, }; static u64 wmt_nand_dma_mask = 0xffffffffUL; static struct platform_device wmt_nand_device = { .name = "nand", .id = 0, .dev = { .dma_mask = &wmt_nand_dma_mask, .coherent_dma_mask = ~0, }, .num_resources = ARRAY_SIZE(wmt_nand_resources), .resource = wmt_nand_resources, }; static struct resource wmt_i2s_resources[] = { [0] = { .start = 0xD80ED800, .end = 0xD80EDBFF, .flags = IORESOURCE_MEM, }, }; static struct resource wmt_pcm_resources[] = { [0] = { .start = 0xD82D0000, .end = 0xD82D0000 + 0x4f, .flags = IORESOURCE_MEM, }, }; static u64 wmt_i2s_dma_mask = 0xffffffffUL; static u64 wmt_pcm_dma_mask = 0xffffffffUL; static struct platform_device wmt_i2s_device = { .name = "wmt-i2s", .id = 0, .dev = { .dma_mask = &wmt_i2s_dma_mask, .coherent_dma_mask = ~0, }, .num_resources = ARRAY_SIZE(wmt_i2s_resources), .resource = wmt_i2s_resources, }; static struct platform_device wmt_pcm_controller_device = { .name = "wmt-pcm-controller", .id = 0, .dev = { .dma_mask = &wmt_pcm_dma_mask, .coherent_dma_mask = ~0, }, .num_resources = ARRAY_SIZE(wmt_pcm_resources), .resource = wmt_pcm_resources, }; static struct platform_device wmt_pcm_dma_device = { .name = "wmt-pcm-dma", .id = 0, }; static struct platform_device wmt_aud_pcm_device = { .name = "wmt-audio-pcm", .id = 0, }; static struct platform_device wmt_i2s_hwdac_device = { .name = "wmt-i2s-hwdac", .id = 0, }; static struct platform_device wmt_switch_device = { .name = "wmt-switch", .id = 0, }; static struct resource wmt_pwm_resources[] = { [0] = { .start = 0xD8220000, .end = 0xD8220000 + 0x44, .flags = IORESOURCE_MEM, }, }; struct platform_device wm8880_device_pwm = { .name = "wm8880-pwm", .id = 0, .num_resources = ARRAY_SIZE(wmt_pwm_resources), .resource = wmt_pwm_resources, }; #ifdef CONFIG_WMT_NEWSPI_SUPPORT static struct spi_board_info wmt_spi_board_info[] = { }; #endif #ifdef CONFIG_WMT_NEWSPI1_SUPPORT static struct spi_board_info wmt_spi1_board_info[] = { }; #endif #ifdef CONFIG_WMT_NEWSPI_SUPPORT static struct wmt_spi_hw wmt_spi_info = { /* spi on wmt can support dma */ .dma_support = SPI_DMA_ENABLE, /* can support 4 slaves when WMT spi as master */ .num_chipselect = MAX_SPI_SLAVE, /* wmt spi support 16bits_per_word? i'm not sure */ .bits_per_word_en = BITS8_PER_WORD_EN, /* wmt spi can support multi-master also, but it seems we do not need it */ .port_mode = PORT_MODE_PTP, /* ssn driven low when enable */ .ssn_ctrl = SSN_CTRL_HARDWARE, /* actual 36bytes, but we use 32bytes */ .fifo_size = SPI_FIFO_SIZE, /* 4Kbytes, same as the DMA */ .max_transfer_length = SPI_MAX_TRANSFER_LENGTH, /* it's really needed? i'm not sure */ .min_freq_hz = SPI_MIN_FREQ_HZ, /* max freq 100Mhz */ .max_freq_hz = SPI_MAX_FREQ_HZ, }; static struct resource wmt_spi_resources[] = { [0] = { .start = SPI0_BASE_ADDR, .end = SPI0_BASE_ADDR + 0xFFFF, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_SPI0, .end = IRQ_SPI0, .flags = IORESOURCE_IRQ, }, }; static u64 wmt_spi_dma_mask = 0xFFFFFFFFUL; static struct platform_device wmt_spi_device = { .name = "wmt_spi_0", .id = 0, .dev = { .dma_mask = &wmt_spi_dma_mask, .coherent_dma_mask = ~0, .platform_data = &wmt_spi_info, }, .num_resources = ARRAY_SIZE(wmt_spi_resources), .resource = wmt_spi_resources, }; #endif #ifdef CONFIG_WMT_NEWSPI1_SUPPORT static struct wmt_spi_hw wmt_spi1_info = { /* spi on wmt can support dma */ .dma_support = SPI_DMA_ENABLE, /* can support 4 slaves when wmt spi as master */ .num_chipselect = MAX_SPI_SLAVE, /* wmt spi support 16bits_per_word? i'm not sure */ .bits_per_word_en = BITS8_PER_WORD_EN, /* wmt spi can support multi-master also, but it seems we do not need it */ .port_mode = PORT_MODE_PTP, /* ssn driven low when enable */ .ssn_ctrl = SSN_CTRL_HARDWARE, /* actual 36bytes, but we use 32bytes */ .fifo_size = SPI_FIFO_SIZE, /* 4Kbytes, same as the DMA */ .max_transfer_length = SPI_MAX_TRANSFER_LENGTH, /* it's really needed? i'm not sure */ .min_freq_hz = SPI_MIN_FREQ_HZ, /* max freq 100Mhz */ .max_freq_hz = SPI_MAX_FREQ_HZ, }; static struct resource wmt_spi1_resources[] = { [0] = { .start = SPI1_BASE_ADDR, .end = SPI1_BASE_ADDR + 0x0000FFFF, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_SPI1, .end = IRQ_SPI1, .flags = IORESOURCE_IRQ, }, }; static u64 wmt_spi1_dma_mask = 0xFFFFFFFFUL; static struct platform_device wmt_spi1_device = { .name = "wmt_spi_1", .id = 1, .dev = { .dma_mask = &wmt_spi1_dma_mask, .coherent_dma_mask = ~0, .platform_data = &wmt_spi1_info, }, .num_resources = ARRAY_SIZE(wmt_spi1_resources), .resource = wmt_spi1_resources, }; #endif #ifdef CONFIG_DRM_MALI static struct platform_device wmt_mali_drm_device = { .name = "mali_drm", .id = -1, }; #endif #ifdef CONFIG_I2S_CODEC_WM8994 static struct regulator_consumer_supply wm8994_fixed_voltage0_supplies[] = { REGULATOR_SUPPLY("DBVDD", "4-001a"), REGULATOR_SUPPLY("AVDD2", "4-001a"), REGULATOR_SUPPLY("CPVDD", "4-001a"), }; static struct regulator_consumer_supply wm8994_fixed_voltage1_supplies[] = { REGULATOR_SUPPLY("SPKVDD1", "4-001a"), REGULATOR_SUPPLY("SPKVDD2", "4-001a"), }; static struct regulator_init_data wm8994_fixed_voltage0_init_data = { .constraints = { .always_on = 1, }, .num_consumer_supplies = ARRAY_SIZE(wm8994_fixed_voltage0_supplies), .consumer_supplies = wm8994_fixed_voltage0_supplies, }; static struct regulator_init_data wm8994_fixed_voltage1_init_data = { .constraints = { .always_on = 1, }, .num_consumer_supplies = ARRAY_SIZE(wm8994_fixed_voltage1_supplies), .consumer_supplies = wm8994_fixed_voltage1_supplies, }; static struct fixed_voltage_config wm8994_fixed_voltage0_config = { .supply_name = "VCC_1.8V_PDA", .microvolts = 1800000, .gpio = -EINVAL, .init_data = &wm8994_fixed_voltage0_init_data, }; static struct fixed_voltage_config wm8994_fixed_voltage1_config = { .supply_name = "V_BAT", .microvolts = 3700000, .gpio = -EINVAL, .init_data = &wm8994_fixed_voltage1_init_data, }; static struct platform_device wm8994_fixed_voltage0 = { .name = "reg-fixed-voltage", .id = 0, .dev = { .platform_data = &wm8994_fixed_voltage0_config, }, }; static struct platform_device wm8994_fixed_voltage1 = { .name = "reg-fixed-voltage", .id = 1, .dev = { .platform_data = &wm8994_fixed_voltage1_config, }, }; static struct regulator_consumer_supply wm8994_avdd1_supply = REGULATOR_SUPPLY("AVDD1", "4-001a"); static struct regulator_consumer_supply wm8994_dcvdd_supply = REGULATOR_SUPPLY("DCVDD", "4-001a"); static struct regulator_init_data wm8994_ldo1_data = { .constraints = { .name = "AVDD1_3.0V", }, .num_consumer_supplies = 1, .consumer_supplies = &wm8994_avdd1_supply, }; static struct regulator_init_data wm8994_ldo2_data = { .constraints = { .name = "DCVDD_1.0V", }, .num_consumer_supplies = 1, .consumer_supplies = &wm8994_dcvdd_supply, }; static struct wm8994_pdata wm8994_platform_data = { /* configure gpio1 function for ADCLRCLK */ .gpio_defaults[0] = 0x0100, /* configure gpio2 & gpio6 function for gpio */ .gpio_defaults[1] = 0x8101, // read-only .gpio_defaults[5] = 0x0001, // output /* configure gpio3/4/5/7 function for AIF2 voice */ .gpio_defaults[2] = 0x8100, .gpio_defaults[3] = 0x8100, .gpio_defaults[4] = 0x8100, .gpio_defaults[6] = 0x0100, /* configure gpio8/9/10/11 function for AIF3 BT */ .gpio_defaults[7] = 0x8100, .gpio_defaults[8] = 0x0100, .gpio_defaults[9] = 0x0100, .gpio_defaults[10] = 0x0100, .ldo[0] = { 0, &wm8994_ldo1_data }, /* XM0FRNB_2 */ .ldo[1] = { 0, &wm8994_ldo2_data }, }; static struct i2c_board_info wm8994_i2c_dev[] __initdata = { {I2C_BOARD_INFO("wm8994", 0x1a), .platform_data = &wm8994_platform_data,}, }; #endif #ifdef CONFIG_ISDBT_MTV23x static struct i2c_board_info isdbt_i2c_dev[] __initdata = { {I2C_BOARD_INFO("isdbti2c", 0x43), .platform_data = NULL,}, }; #endif #ifdef CONFIG_CACHE_L2X0 extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); static void __iomem *l2x0_base; static DEFINE_RAW_SPINLOCK(l2x0_lock); static void wmt_l2x0_disable(void) { unsigned long flags; raw_spin_lock_irqsave(&l2x0_lock, flags); // __l2x0_flush_all(); wmt_smc(WMT_SMC_CMD_PL310CTRL, 0); dsb(); raw_spin_unlock_irqrestore(&l2x0_lock, flags); } #endif static struct platform_device *wmt_devices[] __initdata = { &wmt_uart0_device, &wmt_uart1_device, #ifdef CONFIG_UART_2_3_ENABLE &wmt_uart2_device, &wmt_uart3_device, #endif &wmt_sf_device, #ifdef CONFIG_MTD_WMT_NOR &wmt_nor_device, #endif &wmt_nand_device, &wmt_i2s_device, &wmt_pcm_controller_device, &wmt_pcm_dma_device, &wmt_aud_pcm_device, &wmt_i2s_hwdac_device, // &wmt_pcm_device, &wmt_switch_device, #ifdef CONFIG_WMT_NEWSPI_SUPPORT &wmt_spi_device, #endif #ifdef CONFIG_WMT_NEWSPI1_SUPPORT &wmt_spi1_device, #endif #ifdef CONFIG_DRM_MALI &wmt_mali_drm_device, #endif #ifdef CONFIG_I2S_CODEC_WM8994 &wm8994_fixed_voltage0, &wm8994_fixed_voltage1, #endif &wm8880_device_pwm, }; #ifdef CONFIG_VT1603_IOCTRL_SPI static struct wmt_spi_slave vt1603_codec_info = { .dma_en = SPI_DMA_DISABLE, .bits_per_word = 8, }; static struct spi_board_info vt1603_spi_board_info[] __initdata = { { .modalias = "vt1609", .bus_num = 0, .chip_select = 0, .max_speed_hz = 12000000, .irq = -1, .mode = SPI_CLK_MODE3, .controller_data = &vt1603_codec_info, }, }; #endif static struct i2c_board_info cp2682_i2c_dev[] __initdata = { {I2C_BOARD_INFO("cp2682", (0x2c)),}, }; static char ns_printk_buf[1024]; void sprintk(unsigned int buf, unsigned int len) { local_irq_disable(); printk(ns_printk_buf); wmt_smc(WMT_SMC_CMD_PRINTK_RET, 0); } void notify_log_buf() { wmt_smc(WMT_SMC_CMD_LOGBUFOK, (unsigned int)sprintk); wmt_smc(WMT_SMC_CMD_LOGBUF_ADDR, (unsigned int)virt_to_phys(ns_printk_buf)); } static void wmt_default_idle(void) { if (!need_resched()) { asm("dsb"); asm("wfi"); } local_irq_enable(); } static int __init wmt_init(void) { /* Add for enable user access to pmu */ unsigned char buf[40]; int varlen=40; unsigned int pmu_param; int ret = 0; int vt1603_spi = 0; //0-->spi, 1-->i2c /* Add End */ #ifdef CONFIG_CACHE_L2X0 __u32 power_ctrl = 0; unsigned int onoff = 0; unsigned int aux = 0x3E440000; unsigned int prefetch_ctrl = 0x70000007; unsigned int en_static_address_filtering = 0; unsigned int address_filtering_start = 0xD8000000; unsigned int address_filtering_end = 0xD9000000; unsigned int cpu_trustzone_enabled = 0; unsigned long flags; #endif wmt_gpio_init(); pm_power_off = wmt_power_off; pm_idle = wmt_default_idle; arm_pm_restart = wmt_restart; #ifdef CONFIG_WMT_NEWSPI_SUPPORT spi_register_board_info(wmt_spi_board_info, ARRAY_SIZE(wmt_spi_board_info)); #endif #ifdef CONFIG_WMT_NEWSPI1_SUPPORT spi_register_board_info(wmt_spi1_board_info, ARRAY_SIZE(wmt_spi1_board_info)); #endif #ifdef CONFIG_VT1603_IOCTRL_SPI memset(buf, 0, sizeof(buf)); ret = wmt_getsyspara("wmt.vt1603.bus", buf, &varlen); if (!ret) { sscanf(buf, "%d", &vt1603_spi); // 0-->spi, 1-->i2c } if ( (!vt1603_spi) && // 0-->spi, 1-->i2c ((!wmt_getsyspara("wmt.audio.i2s", buf, &varlen) && (!strncmp(buf, "vt1603", 6) || !strncmp(buf, "vt1609", 6))) || /* audio */ (!wmt_getsyspara("wmt.battery.param", buf, &varlen) && /* battery */ (!strncmp(buf, "vt1603", 6) || !strncmp(buf, "vt1609", 6)))) ) { spi_register_board_info(vt1603_spi_board_info, ARRAY_SIZE(vt1603_spi_board_info)); } #endif #ifdef CONFIG_I2S_CODEC_WM8994 i2c_register_board_info(4, wm8994_i2c_dev, ARRAY_SIZE(wm8994_i2c_dev)); #endif #ifdef CONFIG_ISDBT_MTV23x i2c_register_board_info(4, isdbt_i2c_dev, ARRAY_SIZE(isdbt_i2c_dev)); #endif #ifdef CONFIG_CACHE_L2X0 if (wmt_getsyspara("wmt.l2c.param",buf,&varlen) == 0) sscanf(buf,"%d:%x:%x:%d:%x:%x",&onoff, &aux, &prefetch_ctrl, &en_static_address_filtering, &address_filtering_start, &address_filtering_end); if (wmt_getsyspara("wmt.secure.param",buf,&varlen) == 0) sscanf(buf,"%d",&cpu_trustzone_enabled); if(cpu_trustzone_enabled != 1) cpu_trustzone_enabled = 0; if (onoff == 1) { l2x0_base = ioremap(0xD9000000, SZ_4K); if(cpu_trustzone_enabled == 0) { if (en_static_address_filtering == 1) { writel_relaxed(address_filtering_end, l2x0_base + 0xC04); writel_relaxed((address_filtering_start | 0x01), l2x0_base + 0xC00); } writel_relaxed(0x110, l2x0_base + L2X0_TAG_LATENCY_CTRL); writel_relaxed(0x110, l2x0_base + L2X0_DATA_LATENCY_CTRL); power_ctrl = readl_relaxed(l2x0_base + L2X0_POWER_CTRL) | L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN; writel_relaxed(power_ctrl, l2x0_base + L2X0_POWER_CTRL); writel_relaxed(prefetch_ctrl, l2x0_base + L2X0_PREFETCH_CTRL); } else { if (en_static_address_filtering == 1) { wmt_smc(WMT_SMC_CMD_PL310FILTER_END, address_filtering_end); wmt_smc(WMT_SMC_CMD_PL310FILTER_START, (address_filtering_start | 0x01)); } wmt_smc(WMT_SMC_CMD_PL310TAG_LATENCY, 0x110); wmt_smc(WMT_SMC_CMD_PL310DATA_LATENCY, 0x110); power_ctrl = readl_relaxed(l2x0_base + L2X0_POWER_CTRL) | L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN; wmt_smc(WMT_SMC_CMD_PL310POWER, power_ctrl); wmt_smc(WMT_SMC_CMD_PL310PREFETCH, prefetch_ctrl); raw_spin_lock_irqsave(&l2x0_lock, flags); writel_relaxed(0xffff, l2x0_base + L2X0_INV_WAY); while ( readl_relaxed(l2x0_base + L2X0_INV_WAY) & 0xffff) cpu_relax(); writel_relaxed(0, l2x0_base + L2X0_CACHE_SYNC); raw_spin_unlock_irqrestore(&l2x0_lock, flags); /* enable L2X0 */ wmt_smc(WMT_SMC_CMD_PL310CTRL, 1); } /* 512KB (32KB/way) 16-way associativity */ l2x0_init(l2x0_base, aux, 0); if(cpu_trustzone_enabled != 0) outer_cache.disable = wmt_l2x0_disable; } #endif #ifdef CONFIG_MTD_WMT_SF /* Add for enable user access to ARM11 performance monitor */ if(wmt_getsyspara("wmt.pmu.param",buf,&varlen) == 0) sscanf(buf,"%d",&pmu_param ); if(pmu_param & 0x1){ //enable_user_access(); } #endif /* Add End */ if(cpu_trustzone_enabled == 1) notify_log_buf();//Lch for SecureOS_printk return platform_add_devices(wmt_devices, ARRAY_SIZE(wmt_devices)); } arch_initcall(wmt_init);