一. poweroff关机命令
~ # poweroff ~ # baud=115200, quot=102 w-config: 8bits/char umount: devtmpfs busy - remounted read-only Cannot open value file. umount: can't remount rootfs reabaud=115200, quot=102 w-config: 8bits/char d-only cannot run '/sbin/swapoff': No such file or dirRTL871X: rtw_cmd_thread(wlan0) _rtw_down_sema(&pcmdpriv->cmd_queue_sema) return _FAIL, break ectory The system is going down NOW! Sent SIGTERM to all processes videoin_close Sensor power down Sensor power down I2C removed Sent SIGKILL toPower down. enter to w55fa92_poweroff()
二、内核代码
void w55fa92_poweroff(void) { unsigned long volatile flags; #if defined(CONFIG_RTC_DRV_W55FA92) int rtc_time_out; #endif printk("enter to w55fa92_poweroff() "); msleep(10); // disable LVR __raw_writel(__raw_readl(REG_MISCR) & ~(LVR_RDY | LVR_EN), REG_MISCR); // turn off speaker #if defined(CONFIG_GIANTPLUS_GPM1006D0_320X240) __raw_writel(__raw_readl(REG_GPIOE_OMD) | (1 << 1), REG_GPIOE_OMD); __raw_writel(__raw_readl(REG_GPIOE_DOUT) & ~(1 << 1), REG_GPIOE_DOUT); #endif // turn off video out __raw_writel((__raw_readl(REG_LCM_TVCtl) & ~TVCtl_LCDSrc) | 0x800, REG_LCM_TVCtl); // disable system interrupts local_irq_save(flags); #if defined(CONFIG_RTC_DRV_W55FA92) __raw_writel(__raw_readl(REG_APBCLK) | RTC_CKE, REG_APBCLK); while (1) { rtc_time_out = 0; // enable long time press power disable if ((__raw_readl(REG_RTC_AER) & 0x10000) == 0x0) { // set RTC register access enable password __raw_writel(0xA965, REG_RTC_AER); // make sure RTC register read/write enable while ((__raw_readl(REG_RTC_AER) & 0x10000) == 0x0) { rtc_time_out++; if (rtc_time_out > 0xFFFFFF) { printk("RTC Access Eanble Fail "); break; } } rtc_wait_ready(); if ((__raw_readl(REG_RTC_AER) & 0x10000) == 0x10000) break; } else break; } // RTC will power off __raw_writel((__raw_readl(REG_RTC_PWRON) & ~0x5) | 0x2, REG_RTC_PWRON); #else // turn off power __raw_writel(__raw_readl(REG_GPIOE_OMD) | (1<<9), REG_GPIOE_OMD); __raw_writel(__raw_readl(REG_GPIOE_DOUT) & ~(1<<9), REG_GPIOE_DOUT); #endif // enable system interrupts local_irq_restore(flags); // stop CPU clock //__raw_writel(__raw_readl(REG_AHBCLK) & ~CPU_CKE, REG_AHBCLK); // fix RTC may wakeup fail issue __raw_writel(0x0, REG_AHBCLK); // wait system enter power off while (1) ; } void w55fa92_reboot(void) { unsigned long volatile flags; local_irq_save(flags); printk("enter to w55fa92_reboot() "); // turn off speaker #if defined(CONFIG_GIANTPLUS_GPM1006D0_320X240) __raw_writel(__raw_readl(REG_GPIOE_OMD) | (1 << 1), REG_GPIOE_OMD); __raw_writel(__raw_readl(REG_GPIOE_DOUT) & ~(1 << 1), REG_GPIOE_DOUT); #endif // turn off video out __raw_writel((__raw_readl(REG_LCM_TVCtl) & ~TVCtl_LCDSrc) | 0x800, REG_LCM_TVCtl); // close NAND and SIC engine clock __raw_writel(__raw_readl(REG_AHBCLK) & ~(NAND_CKE|SIC_CKE), REG_AHBCLK); // watchdog reset __raw_writel((__raw_readl(REG_WTCR) & ~(3<<4|1<<10))|0x2C2, REG_WTCR); // wait system enter power off while (1) ; local_irq_restore(flags); } static ssize_t write_clk(struct device *dev, struct device_attribute *attr, const char *buffer, size_t count) { int i; // power down mode if (buffer[0] == 'p' && buffer[1] == 'd') { w55fa92_pm_suspend(1); } #if 0 // idle mode or memory idle mode else if ((buffer[0] == 'i' && buffer[1] == 'd') || (buffer[0] == 'm' && buffer[1] == 'i')) { w55fa92_pm_idle(); } #endif #if defined(CONFIG_RTC_DRV_W55FA92) // RTC power off mode else if (buffer[0] == 'r' && buffer[1] == 'p' && buffer[2] == 'o') { w55fa92_poweroff(); } #else // power off mode else if (buffer[0] == 'p' && buffer[1] == 'o') { w55fa92_poweroff(); } #endif // power reset mode else if (buffer[0] == 'p' && buffer[1] == 'r') { w55fa92_reboot(); } // CPU:PLL clock change else { u32 pll_clock, sys_clock, cpu_clock, apb_clock, vpost_clock; u8 vpost_div_N0, vpost_div_N1; char clock_buf[64]; char *clock1, *clock2, *next; strncpy(clock_buf, buffer, count); next = &clock_buf[0]; pll_clock = w55fa92_upll_clock; clock1 = strsep(&next, ":"); //printk("clock1 = %s ", clock1); cpu_clock = simple_strtol(clock1, NULL, 10) * 1000; if (cpu_clock == 0) { printk("Command "%s" does not support !! ", clock1); return -1; } if (next) { clock2 = strsep(&next, ":"); //printk("clock2 = %s ", clock2); pll_clock = simple_strtol(clock2, NULL, 10) * 1000; if (pll_clock == 0) { printk("Command "%s" does not support !! ", clock2); return -1; } } if (pll_clock % cpu_clock) { printk("UPLL clock(%d) is not a multiple of CPU clock(%d) !! ", pll_clock, cpu_clock); return -1; } #if defined(CONFIG_FB_W55FA92) vpost_div_N0 = (__raw_readl(REG_CLKDIV1) & VPOST_N0) + 1; vpost_div_N1 = ((__raw_readl(REG_CLKDIV1) & VPOST_N1) >> 8) + 1; vpost_clock = pll_clock / (vpost_div_N0 * vpost_div_N1); if (cpu_clock > vpost_clock*2) { sys_clock = cpu_clock; } else { for (i = 1; ; i++) { sys_clock = cpu_clock * i * 2; if ((i > 8) || (sys_clock > pll_clock)) { printk("Cannot get valid System clock !! "); return -1; } if ((sys_clock>(vpost_clock*2)) && ((pll_clock%sys_clock)==0)) break; } } #else sys_clock = cpu_clock; #endif apb_clock = (cpu_clock == sys_clock) ? cpu_clock/4 : cpu_clock/2; #if CPU_DEBUG printk("vpost_clock = %d ", vpost_clock); printk("pll_clock = %d ", pll_clock); printk("sys_clock = %d ", sys_clock); printk("cpu_clock = %d ", cpu_clock); printk("apb_clock = %d ", apb_clock); #endif // PLL:SYS:CPU:AHB:APB = pll_clock:sys_clock:cpu_clock:sys_clock/2:apb_clock set_system_clocks(pll_clock, sys_clock, cpu_clock, apb_clock); } return count; } /* Attach the sysfs write method */ DEVICE_ATTR(clock, 0644, read_clk, write_clk); /* Attribute Descriptor */ static struct attribute *clk_attrs[] = { &dev_attr_clock.attr, NULL }; /* Attribute group */ static struct attribute_group clk_attr_group = { .attrs = clk_attrs, }; static int __init w55fa92_system_clock_init(void) { /* Register a platform device */ printk("register clock device ");
///sys/devices/w55fa92-clk sys_clk = platform_device_register_simple("w55fa92-clk", -1, NULL, 0); if (sys_clk == NULL) printk("register failed "); sysfs_create_group(&sys_clk->dev.kobj, &clk_attr_group); sram_vaddr = ioremap(0xFF000000, 4*1024); return 0; } module_init(w55fa92_system_clock_init);