<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # linux SPI驅動分析 linux下驅動都是分層結構,降低耦合度。 下面從 總線,設備, 驅動 分別分析linux下的SPI驅動。 ## 驅動目錄分析 driver/spi下 spi-xxx芯片.c 芯片的spi控制器,如spi-sun6i.c spi-bitbang.c 位段 spi-gpio.c gpio模擬spi spi-slave-system-control.c 從設備 spi-slave-time.c 從設備 spi.c spidev.c 設備 ~~~ pure_initcall core_initcall core_initcall_sync postcore_initcall postcore_initcall_sync arch_initcall arch_initcall_sync subsys_initcall subsys_initcall_sync fs_initcall fs_initcall_sync rootfs_initcall device_initcall device_initcall_sync late_initcall late_initcall_sync ~~~ ### spi.c spi核心操作 postcore_initcall(spi_init); ~~~ buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); //用于SPI數據傳輸 …… status = bus_register(&spi_bus_type); // /sys/bus下注冊總線 …… status = class_register(&spi_master_class); // /sys/class 下注冊類 …… if (IS_ENABLED(CONFIG_SPI_SLAVE)) { status = class_register(&spi_slave_class); // /sys/class下注冊從機類 …… } if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_register(&spi_of_notifier)); if (IS_ENABLED(CONFIG_ACPI)) WARN_ON(acpi_reconfig_notifier_register(&spi_acpi_notifier)); //電源管理 return 0; ~~~ ~~~ struct bus_type spi_bus_type = { .name = "spi", .dev_groups = spi_dev_groups, .match = spi_match_device, //總線作用即是匹配設備與驅動 .uevent = spi_uevent, //發送總線事件提醒 }; static struct class spi_master_class = { .name = "spi_master", .owner = THIS_MODULE, .dev_release = spi_controller_release, .dev_groups = spi_master_groups, }; ~~~ #### 總線注冊 設備和驅動都是掛載在總線上。 分析總線注冊函數bus_register,首先申請了一個subsys_private結構體內存。 該結構體中包含了三個kset結構,分別是`struct kset subsys、struct kset *devices_kset和struct kset *drivers_kset。` 當每次設備插入,或者驅動加載,就會分配一個device或者device_drive結構,將其加入drivers或devices(kset結構)鏈表中。后面就可以通過總線來匹配設備和驅動了。 總線目錄名為spi,即/sys/bus/spi。 匹配函數: ~~~ static int spi_match_device(struct device *dev, struct device_driver *drv) { const struct spi_device *spi = to_spi_device(dev); const struct spi_driver *sdrv = to_spi_driver(drv); /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) //驅動和設備匹配,則返回 return 1; if (sdrv->id_table) //id匹配 return !!spi_match_id(sdrv->id_table, spi); return strcmp(spi->modalias, drv->name) == 0; //別名匹配 } ~~~ #### spi統計接口 ~~~ static struct attribute *spi_device_statistics_attrs[] = { &dev_attr_spi_device_messages.attr, &dev_attr_spi_device_transfers.attr, &dev_attr_spi_device_errors.attr, &dev_attr_spi_device_timedout.attr, &dev_attr_spi_device_spi_sync.attr, &dev_attr_spi_device_spi_sync_immediate.attr, &dev_attr_spi_device_spi_async.attr, &dev_attr_spi_device_bytes.attr, &dev_attr_spi_device_bytes_rx.attr, &dev_attr_spi_device_bytes_tx.attr, &dev_attr_spi_device_transfer_bytes_histo0.attr, …… &dev_attr_spi_device_transfer_bytes_histo16.attr, &dev_attr_spi_device_transfers_split_maxsize.attr, } ~~~ #### 驅動相關 ~~~ static int spi_drv_probe(struct device *dev) //設置時鐘頻率,注冊中斷 int spi_add_device(struct spi_device *spi) //增加一個設備,設置模組,cs等,再調用父類device的方法 spi_unregister_device //最后調用實際控制器里的操作方法 spi_set_cs spi_map_buf spi_map_msg spi_transfer_one_message __spi_pump_messages spi_get_next_queued_message spi_finalize_current_message spi_start_queue spi_start_queue of_register_spi_device spi_register_controller devm_spi_register_controller spi_sync spi_write_then_read ~~~ ### spidev.c 一個通用的spidev設備驅動。 spi設備的操作。封裝了spi.c里的東西。 設備匹配: ~~~ static const struct of_device_id spidev_dt_ids[] = { { .compatible = "rohm,dh2228fv" }, { .compatible = "lineartechnology,ltc2488" }, { .compatible = "ge,achc" }, { .compatible = "semtech,sx1301" }, {}, }; ~~~ ### gpio模擬spi spi-bitbang.c 位段形式的spi控制器 spi-gpio.c gpio模擬spi的具體實現,由spi-bitbang調用。 其它一些芯片的.c下也有實現txrx_word等,可以使用。 ~~~ //前面有一些具體的操作io函數 static inline void setsck(const struct spi_device *spi, int is_on) static inline void setmosi(const struct spi_device *spi, int is_on) static inline int getmiso(const struct spi_device *spi) //發送相關的調用了bitbang的函數 static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits) { return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits); } static const struct of_device_id spi_gpio_dt_ids[] = { { .compatible = "spi-gpio" }, {} }; MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids); static int spi_gpio_probe_dt(struct platform_device *pdev) {} static struct platform_driver spi_gpio_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(spi_gpio_dt_ids), }, .probe = spi_gpio_probe, .remove = spi_gpio_remove, }; ~~~ ### 從機相關 spi-slave-system-control.c 從設備 spi-slave-time.c 從設備 ### 芯片spi控制器 以spi-sun6i.c為例 ~~~ struct sun6i_spi { struct spi_master *master; void __iomem *base_addr; struct clk *hclk; struct clk *mclk; struct reset_control *rstc; struct completion done; const u8 *tx_buf; u8 *rx_buf; int len; unsigned long fifo_depth; }; static const struct of_device_id sun6i_spi_match[] = { { .compatible = "allwinner,sun6i-a31-spi", .data = (void *)SUN6I_FIFO_DEPTH }, { .compatible = "allwinner,sun8i-h3-spi", .data = (void *)SUN8I_FIFO_DEPTH }, {} }; MODULE_DEVICE_TABLE(of, sun6i_spi_match); static const struct dev_pm_ops sun6i_spi_pm_ops = { .runtime_resume = sun6i_spi_runtime_resume, .runtime_suspend = sun6i_spi_runtime_suspend, }; //填充spi_master的參數 static int sun6i_spi_probe(struct platform_device *pdev) { sspi->master = master; sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev); master->max_speed_hz = 100 * 1000 * 1000; master->min_speed_hz = 3 * 1000; master->set_cs = sun6i_spi_set_cs; master->transfer_one = sun6i_spi_transfer_one; master->num_chipselect = 4; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; master->bits_per_word_mask = SPI_BPW_MASK(8); master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; master->max_transfer_size = sun6i_spi_max_transfer_size; sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); } static struct platform_driver sun6i_spi_driver = { .probe = sun6i_spi_probe, .remove = sun6i_spi_remove, .driver = { .name = "sun6i-spi", .of_match_table = sun6i_spi_match, .pm = &sun6i_spi_pm_ops, }, }; module_platform_driver(sun6i_spi_driver); /* module_platform_driver(xxx); 最終展開后就是如下形式: static int __init xxx_init(void) { return platform_driver_register(&xxx); } module_init(xxx_init); static void __exit xxx_init(void) { return platform_driver_unregister(&xxx); } module_exit(xxx_exit); */ ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看