加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

让MT7620完美支持32M SPI Flash(W25Q256) — 兼谈设备驱动中的sh

发布时间:2020-12-15 19:52:33 所属栏目:百科 来源:网络整理
导读:让MT7620完美支持32M SPI Flash(W25Q256) — 兼谈设备驱动中的shutdown方法 前言 OpenWrt的最新kernel(3.14.28)已经能够支持32M SPI Flash的读写以及擦除操作.然而,可能是系统考虑不周,亦或是MT7620系统的BUG,在配置了W25Q256的MT7620开发板系统上,无法soft

让MT7620完美支持32M SPI Flash(W25Q256) — 兼谈设备驱动中的shutdown方法

前言

OpenWrt的最新kernel(3.14.28)已经能够支持32M SPI Flash的读写以及擦除操作.然而,可能是系统考虑不周,亦或是MT7620系统的BUG,在配置了W25Q256的MT7620开发板系统上,无法soft reset!经过查阅相关资料,发现,MT7620默认支持24bit(3byte)的spi地址模式,而要支持32M以上的spi flash,则必须切换到32bit(4byte)地址模式.在soft reset的时候,spi停留在了32bit模式,没有切换回默认的24bit模式,导致reset后,MT7620在默认的24bit模式,无法和32bit模式的spi通讯,系统死机.那么问题来了:如何在soft reset时刻,让spi flash切换回24bit模式呢?本文通过设备驱动中的一个shutdown方法来解决这个问题.

背景知识

在linux源代码kernel目录下,有一个reboot.c文件,里面暴露了一个register_reboot_notifier方法,可以让kernel中的代码有机会获得reboot的通知,当我们继续分析reboot.c的代码时,会发现更有意思的东西:

/** * kernel_restart - reboot the system *  @cmd: pointer to buffer containing command to execute for restart * or %NULL * * Shutdown everything and perform a clean reboot. * This is 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 systemn");  
        else  
            pr_emerg("Restarting system with command '%s'n",cmd);  
        kmsg_dump(KMSG_DUMP_RESTART);  
        machine_restart(cmd);  
    }

在kernel_restart中,又调用了kernel_restart_prepare方法:

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在drivers/base/core.c中实现:

/** * device_shutdown - call ->shutdown() on each device to shutdown. */  
    void device_shutdown(void)  
    {  
        struct device *dev,*parent;  

        spin_lock(&devices_kset->list_lock);  
        /* * Walk the devices list backward,shutting down each in turn. * Beware that device unplug events may also start pulling * devices offline,even as the system is shutting down. */  
        while (!list_empty(&devices_kset->list)) {  
            dev = list_entry(devices_kset->list.prev,struct device,kobj.entry);  

            /* * hold reference count of device's parent to * prevent it from being freed because parent's * lock is to be held */  
            parent = get_device(dev->parent);  
            get_device(dev);  
            /* * Make sure the device is 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,"shutdownn");  
                dev->bus->shutdown(dev);  
            } else if (dev->driver && dev->driver->shutdown) {  
                //if (initcall_debug) manfeel 
                    dev_info(dev,"shutdownn");  
                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();  
    }

通过阅读代码,我们不难发现,在device_shutdown中,枚举了设备的shutdown方法,如果存在该方法,则会调用之.

于是,32M spi flash的reset方法喷薄而出.

解决办法

转到drivers/mtd/devices/m25p80.c

修改如下代码:

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,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 deep power-down modes,which * should clearly be entered on suspend() to minimize power use. * And also when they're otherwise idle... */  
    };

总结

通过注册设备的shutdown方法,让我们有机会在系统重启的时刻,做一些deinit的操作.通过此种方法来复位spi flash,优雅而简洁.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读