1. 程式人生 > >SPI設備註冊過程

SPI設備註冊過程

開發板:tiny4412SDK + S702 + 4GB Flash
要移植的核心版本:Linux-4.4.0 (支援device tree)
u-boot版本:友善之臂自帶的 U-Boot 2010.12
busybox版本:busybox 1.25

目標:
同 i2c 一樣,分析 spi 裝置的註冊過程,其實是一模一樣的。

int spi_register_master(struct spi_master *master)  //註冊控制器驅動
    of_register_spi_devices(master);
        for_each_available_child_of_node(master->dev.of_node, nc)
//控制器節點的子節點 of_register_spi_device(master, nc);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
static struct spi_device * of_register_spi_device(struct spi_master *master, struct device_node *nc)
{
    struct spi_device *spi;
    int rc;
    u32 value;

    /* 分配一個 spi device ,從屬於 master*/
    spi = spi_alloc_device(master);

    /* 獲取 compatibel 屬性,具體看後邊 */
rc = of_modalias_node(nc, spi->modalias, sizeof(spi->modalias)); /* 獲取 reg 屬性作為片選編號 */ rc = of_property_read_u32(nc, "reg", &value); spi->chip_select = value; /* mode 設定 */ if (of_find_property(nc, "spi-cpha", NULL)) spi->mode |= SPI_CPHA; if (of_find_property(nc, "spi-cpol"
, NULL)) spi->mode |= SPI_CPOL; if (of_find_property(nc, "spi-cs-high", NULL)) spi->mode |= SPI_CS_HIGH; if (of_find_property(nc, "spi-3wire", NULL)) spi->mode |= SPI_3WIRE; if (of_find_property(nc, "spi-lsb-first", NULL)) spi->mode |= SPI_LSB_FIRST; /* Device DUAL/QUAD mode */ if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) { switch (value) { case 1: break; case 2: spi->mode |= SPI_TX_DUAL; break; case 4: spi->mode |= SPI_TX_QUAD; break; default: dev_warn(&master->dev, "spi-tx-bus-width %d not supported\n", value); break; } } if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) { switch (value) { case 1: break; case 2: spi->mode |= SPI_RX_DUAL; break; case 4: spi->mode |= SPI_RX_QUAD; break; default: dev_warn(&master->dev, "spi-rx-bus-width %d not supported\n", value); break; } } /* 獲取最大速度 */ rc = of_property_read_u32(nc, "spi-max-frequency", &value); spi->max_speed_hz = value; /* Store a pointer to the node in the device structure */ of_node_get(nc); spi->dev.of_node = nc; /* 註冊 spi device */ rc = spi_add_device(spi); return spi; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
int of_modalias_node(struct device_node *node, char *modalias, int len)
{
    const char *compatible, *p;
    int cplen;

    compatible = of_get_property(node, "compatible", &cplen);
    if (!compatible || strlen(compatible) > cplen)
        return -ENODEV;
    p = strchr(compatible, ',');
    strlcpy(modalias, p ? p + 1 : compatible, len);//如果compatibel屬性中有“,”則取“,”之後的內容,否則取全部,它作為匹配依據
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
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);  

    if (sdrv->id_table)  
        return !!spi_match_id(sdrv->id_table, spi);  

    return strcmp(spi->modalias, drv->name) == 0;  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, const struct spi_device *sdev)
{
    while (id->name[0]) {
        if (!strcmp(sdev->modalias, id->name))
            return id;
        id++;
    }
    return NULL;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

啟動報錯:

[    0.962673] spi spi0.0: child node 'controller-data' not found               
[    0.968455] spi spi0.0: No CS for SPI(0)                                     
[    0.972360] s3c64xx-spi 13920000.spi: can't setup spi0.0, status -19         
[    0.978693] spi_device register error /[email protected]13920000/[email protected]0                 
[    0.984339] spi_master spi0: Failed to create SPI device for /[email protected]13920000/s0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
int spi_add_device(struct spi_device *spi)
{
    static DEFINE_MUTEX(spi_add_lock);
    struct spi_master *master = spi->master;
    struct device *dev = master->dev.parent;
    int status;

    /* Chipselects are numbered 0..max; validate. */
    if (spi->chip_select >= master->num_chipselect) 

    /* Set the bus ID string */
    spi_dev_set_name(spi);

    mutex_lock(&spi_add_lock);

    status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);

    if (master->cs_gpios)
        spi->cs_gpio = master->cs_gpios[spi->chip_select];

    status = spi_setup(spi);
    if (status < 0) {
        dev_err(dev, "can't setup %s, status %d\n", dev_name(&spi->dev), status);
        goto done;
    }

    /* Device may be bound to an active driver when this returns */
    status = device_add(&spi->dev);
    if (status < 0)
        dev_err(dev, "can't add %s, status %d\n",
                dev_name(&spi->dev), status);
    else
        dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));

done:
    mutex_unlock(&spi_add_lock);
    return status;
}
EXPORT_SYMBOL_GPL(spi_add_device);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
static int s3c64xx_spi_setup(struct spi_device *spi)
{
    struct s3c64xx_spi_csinfo *cs = spi->controller_data;
    struct s3c64xx_spi_driver_data *sdd;
    struct s3c64xx_spi_info *sci;
    int err;

    sdd = spi_master_get_devdata(spi->master);
    if (spi->dev.of_node) {
        cs = s3c64xx_get_slave_ctrldata(spi);
        spi->controller_data = cs;
    } else if (cs) {
        /* On non-DT platforms the SPI core will set spi->cs_gpio
         * to -ENOENT. The GPIO pin used to drive the chip select
         * is defined by using platform data so spi->cs_gpio value
         * has to be override to have the proper GPIO pin number.
         */
        spi->cs_gpio = cs->line;
    }

    if (IS_ERR_OR_NULL(cs)) {
        dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select);
        return -ENODEV;
    }

    if (!spi_get_ctldata(spi)) {
        if (gpio_is_valid(spi->cs_gpio)) {
            err = gpio_request_one(spi->cs_gpio, GPIOF_OUT_INIT_HIGH,
                           dev_name(&spi->dev));
            if (err) {
                dev_err(&spi->dev,
                    "Failed to get /CS gpio [%d]: %d\n",
                    spi->cs_gpio, err);
                goto err_gpio_req;
            }
        }

        spi_set_ctldata(spi, cs);
    }

    sci = sdd->cntrlr_info;

    pm_runtime_get_sync(&sdd->pdev->dev);

    /* Check if we can provide the requested rate */
    if (!sdd->port_conf->clk_from_cmu) {
        u32 psr, speed;

        /* Max possible */
        speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1);

        if (spi->max_speed_hz > speed)
            spi->max_speed_hz = speed;

        psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
        psr &= S3C64XX_SPI_PSR_MASK;
        if (psr == S3C64XX_SPI_PSR_MASK)
            psr--;

        speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
        if (spi->max_speed_hz < speed) {
            if (psr+1 < S3C64XX_SPI_PSR_MASK) {
                psr++;
            } else {
                err = -EINVAL;
                goto setup_exit;
            }
        }

        speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
        if (spi->max_speed_hz >= speed) {
            spi->max_speed_hz = speed;
        } else {
            dev_err(&spi->dev, "Can't set %dHz transfer speed\n",
                spi->max_speed_hz);
            err = -EINVAL;
            goto setup_exit;
        }
    }

    pm_runtime_mark_last_busy(&sdd->pdev->dev);
    pm_runtime_put_autosuspend(&sdd->pdev->dev);
    if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
        writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
    return 0;

setup_exit:
    pm_runtime_mark_last_busy(&sdd->pdev->dev);
    pm_runtime_put_autosuspend(&sdd->pdev->dev);
    /* setup() returns with device de-selected */
    if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
        writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);

    if (gpio_is_valid(spi->cs_gpio))
        gpio_free(spi->cs_gpio);
    spi_set_ctldata(spi, NULL);

err_gpio_req:
    if (spi->dev.of_node)
        kfree(cs);

    return err;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( struct spi_device *spi)
{
    struct s3c64xx_spi_csinfo *cs;
    struct device_node *slave_np, *data_np = NULL;
    u32 fb_delay = 0;

    slave_np = spi->dev.of_node;
    if (!slave_np) {
        dev_err(&spi->dev, "device node not found\n");
        return ERR_PTR(-EINVAL);
    }

    data_np = of_get_child_by_name(slave_np, "controller-data");
    if (!data_np) {
        dev_err(&spi->dev, "child node 'controller-data' not found\n");
        return ERR_PTR(-EINVAL);
    }

    cs = kzalloc(sizeof(*cs), GFP_KERNEL);
    if (!cs) {
        of_node_put(data_np);
        return ERR_PTR(-ENOMEM);
    }

    of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay);
    cs->fb_delay = fb_delay;
    of_node_put(data_np);
    return cs;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

最開始,就是因為沒有指定 controller-data 導致裝置無法匹配到驅動程式,查了半天。下面給出後面要寫的 spi flash 的裝置樹:

&spi_0 {
        status = "okay";

        cs-gpios = <&gpb 1 GPIO_ACTIVE_HIGH>;
        [email protected]0 {
                compatible = "tiny4412,spi_flash";
                spi-max-frequency = <10000000>;
                reg = <0>;
                controller-data {
                        samsung,spi-feedback-delay = <0>;
                };
        };
};


相關推薦

裝置樹學習之(九)SPI備註過程

開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busy

SPI備註過程

開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busybox 1.25 目標: 同 i

I2C匯流排備註過程

轉自 http://lhsblog01.blog.163.com/blog/static/1020045192010221103944423/i2c bus i2c匯流排使用 platform_device實現, 匯流排驅動用platform_driver實現. 在註冊i2c_bus時,會把與這個BUS相

QCom MSM平臺顯示屏Framebuffer備註過程

本文是Android Display部分分析的一部分,描述屏Framebuffer設備註冊過程。 QC MSM7xxx/MSM8xxx平臺本身就提供了很多介面的屏的支援,每種屏對應一個驅動檔案。由於QC MSM平臺顯示驅動架構做了絕大部分的工作,驅動一塊新的屏僅需要做很少量的工作。下面的過程是屏Frameb

v4l2 video備註和呼叫過程

一、 註冊一個video_device裝置 它代表系統/dev/videox裝置節點的實際的物理裝置。 下邊一核心版本2.6.32種成熟的omap2432處理器攝像頭控制器模組驅動為例分析: 下邊的程式碼在driver/media/video/omap24xxcam.c中

十二 v4l2 video備註和呼叫過程

一、 註冊一個video_device裝置 它代表系統/dev/videox裝置節點的實際的物理裝置。 下邊一核心版本2.6.32種成熟的omap2432處理器攝像頭控制器模組驅動為例分析: 下邊的程式碼在driver/media/video/omap24xxcam.c中 1、Video device的操

Linux:驅動之字元備註新介面(未完)

驅動之字元設備註冊新介面 目前尚不是最終版本,還望有心人自己學習的時候,把自己整合的知識點相關的答案也好問題也好,或者實踐過程中的一些操作截圖,再或者其他的一些想要分享材料發給筆者郵箱:[email protected],我們一起完善這篇部落格!筆者寫這篇部

備註、驅動註冊以及雜項備註之間的關係

1.裝置宣告是在平臺檔案/home/leizi/android/iTop4412_Kernel_3.0/arch/arm/mach-exynos/mach-itop4412.c中,如下圖,並且裝置名稱是led_two. 核心編譯之後,s3c_device_leds_ctl

platform_device_系列函式及其備註的作用

platform_device_系列函式,實際上是註冊了一個叫platform的虛擬匯流排。使用約定是如果一個不屬於任何匯流排的裝置,例如藍芽,串列埠等裝置,都需要掛在這個虛擬總線上。 river/base/platform.c //platform裝置宣告 struct

Linux kernel 有關 spi 備樹參數解析

-c enable pre ann driver error ola state AC 最近做了一個 spi 設備驅動從板級設備驅動升級到設備樹設備驅動,這其中要了解 spi 設備樹代碼的解析。 設備樹配置如下: 503 &spi0 { 504 statu

ISE主備註和同步

Synchronize Primary and Secondary Cisco ISE Nodes You can make configuration changes to Cisco ISE only through the Primary PAN. The configuration changes g

Spring ConfigurationClassPostProcessor Bean解析及自注過程

一、Bean的自注冊過程    二、自注冊過程說明 ConfigurationClassParser解析流程    1、處理@PropertySources註解,配置資訊的解析   2、處理@ComponentScan註解:使用ComponentScanAnnotationParser掃描baseP

linux驅動編寫32位與64位備註意事項

  Linux 64 位體系結構     不幸的是,C 程式語言並沒有提供一種機制來新增新的基本資料型別。因此,提供 64 位的定址和整數運算能力必須要修改現有資料型別的繫結或對映,或者向 C 語言中新增新的資料型別。     表 1. 32 位和 64 位資料模型 ILP32 LP64 LLP64

Mysql儲存過程4:mysql變量

from 默認 pan procedure weight use mysql變量 sql 寫法 默認全局變量是兩個@@開頭, 可用show variables查看所有默認變量: @@user #declare定義變量只能用在儲存過程中 #declare 變量名 數據類型

Nhibernate/Hibernate 使用存儲過程 多參數

ner map ini names project als service location work <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:n

(轉)關於Tomcat的點點滴滴(體系架構、處理http請求的過程、安裝和配置、目錄結構、置壓縮和對中文文件名的支持、以及Catalina這個名字的由來……等)

https 設置 重啟 specific 調用 持久化數據 所在 original apps 轉自:http://itfish.net/article/41668.html 總結Tomcat的體系架構、處理http請求的過程、安裝和配置、目錄結構、設置壓縮和對中文文件名

H5調用備攝像頭和系統相

camera 系統相冊 capture 調用 設備 accept 攝像 acc ima 1.調用設備攝像頭 <input type="file" accept="image/*" capture="camera"> 2.調用系統相冊 <inp

STM32F407 讀保護,寫保護,解鎖過程【芯片已置讀保護,無法讀取更多信息】

寫保護 stm32f407 讀保護 解鎖過程 硬件準備:CH340 USB轉TTL串口一個STM32F407 板子一塊設置從ISP啟動軟件準備:1,flash_loader_demo_v2.8.0.exe 或者 FlashLoader Demonstrator 2.8.0.msi 都可以下載地址:

置Sql server用戶對表、視圖、存儲過程、架構的增刪改查權限

例如 ont 函數 權限控制 str 角色 -s 簡單 管理 根據數據庫Schema限制用戶對數據庫的操作行為 授予Shema dbo下對象的定義權限給某個用戶(也就是說該用戶可以修改架構dbo下所有表/視圖/存儲過程/函數的結構) use [Your DB N

MPS添加管理備實例NS的過程

-a enable pan pass password ren eat gateway tor MPS添加管理設備實例NS的過程 MPS添加實例NS設備節點: Jan 25 18:25:05 <local0.info> mpsvpx mas_se