Preface
OpenWrt's newest kernel (3.14.28) has been able to support both read-write and erase operations for 32M SPI Flash. However, the system may be poorly considered or a bug in the MT7620 system, on the W25Q256 Development Board system configured MT7620, Unable to soft reset! after consulting the relevant data, found that the MT7620 default support 24bit (3byte) SPI address mode, and to support more than 32M of SPI Flash, you must switch to 32bit (4byte) address mode. At soft reset. , the SPI stays in the 32bit mode, does not switch back to the default 24bit mode, resulting in reset, MT7620 in the default 24bit mode, cannot and 32bit mode SPI communication, the system freezes. Then the question came: How to soft the reset moment, let the SPI Flash switch back to 24bit mode? This paper solves this problem by means of a shutdown method in device driver.
Background Knowledge
In the Linux source code kernel directory, there is a reboot.c file, which exposes a Register_reboot_notifier method, you can let kernel in the code to get reboot notification, When we continue to analyze Reboot.c's code, we find something more interesting:
/**
* kernel_restart-reboot the system
* @cmd: Pointer to buffer containing command-to-execute for Resta RT
* or%null
*
* Shutdown Everything and perform a clean reboot.
* This is the not safe-to-call in interrupt context.
*
/void Kernel_restart (char *cmd)
{
kernel_restart_prepare (cmd);
Migrate_to_reboot_cpu ();
Syscore_shutdown ();
if (!cmd)
Pr_emerg ("Restarting system\n");
else
Pr_emerg ("Restarting system with command '%s ' \ n", cmd);
Kmsg_dump (Kmsg_dump_restart);
Machine_restart (cmd);
}
In Kernel_restart, the Kernel_restart_prepare method is called:
void Kernel_restart_prepare (char *cmd)
{
blocking_notifier_call_chain (&reboot_notifier_list, SYS_ RESTART, cmd);
System_state = System_restart;
Usermodehelper_disable ();
Device_shutdown ();
}
Device_shutdown is implemented in DRIVERS/BASE/CORE.C:
/** * Device_shutdown-call->shutdown () on the device to shutdown.
*/void Device_shutdown (void) {struct device *dev, *parent;
Spin_lock (&devices_kset->list_lock);
/* * Walk the devices list backward, shutting down all in turn.
* Beware that device unplug events may also start pulling * devices offline, even as the system was shutting down. */while (!list_empty (&devices_kset->list)) {dev = list_entry (devices_kset->list.prev, struct device, KO
Bj.entry); /* * Hold reference count of device's parent to * prevent it from being freed because parent's * lock is to be he
LD */parent = Get_device (dev->parent);
Get_device (Dev);
/* * Make sure the device was off the Kset list, in the * event that Dev->*->shutdown () doesn ' t remove it.
*/List_del_init (&dev->kobj.entry);
Spin_unlock (&devices_kset->list_lock); /* Hold lock to avoid race with probe/release */if (parent) Device_lock (parent);
Device_lock (Dev);
/* Don ' t allow any more runtime suspends */Pm_runtime_get_noresume (dev);
Pm_runtime_barrier (Dev);
Manfeel, add debug Info//dev_info (Dev, "Search shutdown method...\n");
if (Dev->bus && dev->bus->shutdown) {//if (initcall_debug) manfeel dev_info (Dev, "shutdown\n");
Dev->bus->shutdown (Dev); } else if (Dev->driver && dev->driver->shutdown) {//if (initcall_debug) manfeel dev_info (Dev, "sh
Utdown\n ");
Dev->driver->shutdown (Dev);
} device_unlock (Dev);
if (parent) device_unlock (parent);
Put_device (Dev);
Put_device (parent);
Spin_lock (&devices_kset->list_lock);
} spin_unlock (&devices_kset->list_lock);
Async_synchronize_full (); }
By reading the code, it is not difficult to see that in Device_shutdown, the shutdown method of the device is enumerated, and if the method is present, it is called.
As a result, the Reset method of the 32M SPI Flash is gushing out.
Solutions
Go to Drivers/mtd/devices/m25p80.c
Modify the following code:
static int m25p_remove (struct spi_device *spi)
{
struct m25p *flash = Spi_get_drvdata (SPI);
Manfeel note:add SPI Flash reset code
flash->command[0] = 0x66;
Spi_write (Flash->spi, Flash->command, 1);
Flash->command[0] = 0x99;
Spi_write (Flash->spi, Flash->command, 1);
/* Clean up MTD stuff. *
/return Mtd_device_unregister (&FLASH->MTD);
}
static struct Spi_driver M25p80_driver = {
. Driver = {
. Name = "M25p80",
. Owner = this_module,
},
. id_table = M25p_ids,
. Probe = M25p_probe,
. Remove = M25p_remove,
// Manfeel, add shutdown method to reset SPI Flash
. Shutdown = m25p_remove,/
* Revisit:many of these chips have de EP Power-down modes, which
* should clearly is entered on suspend () to minimize power use.
* and also when they ' re otherwise idle ...
*/
};
Summary
By registering the device's shutdown method, we have the opportunity to do some deinit operation at the time of the system reboot. This method resets the SPI flash in an elegant and concise manner.