Linux spi子操作系統(tǒng)驅(qū)動(dòng)分析 |
發(fā)布時(shí)間: 2012/8/24 13:58:57 |
2.6.18內(nèi)核下已經(jīng)添加了完整的spi子系統(tǒng)了,參考mtd的分析,將從下到上層,再從上到下層的對其進(jìn)行分析。
以下先從下到上的進(jìn)行分析: driver/spi下有兩個(gè)底層相關(guān)的spi驅(qū)動(dòng)程序: spi_s3c24xx.c和spi_s3c24xx_gpio.c 其中spi_s3c24xx.c是基于s3c24xx下相應(yīng)的spi接口的驅(qū)動(dòng)程序,spi_s3c24xx_gpio.c允許用戶指定3個(gè)gpio口,分別充當(dāng)spi_clk、spi_mosi和spi_miso接口,模擬標(biāo)準(zhǔn)的spi總線。 s3c2410自帶了兩個(gè)spi接口(spi0和spi1),在此我只研究基于s3c2410下spi接口的驅(qū)動(dòng)程序spi_s3c24xx.c。 首先從spi驅(qū)動(dòng)的檢測函數(shù)進(jìn)行分析: static int s3c24xx_spi_probe(struct platform_device *pdev) { struct s3c24xx_spi *hw; struct spi_master *master; struct spi_board_info *bi; struct resource *res; int err = 0; int i; /* pi_alloc_master函數(shù)申請了struct spi_master+struct s3c24xx_spi大小的數(shù)據(jù), * spi_master_get_devdata和pi_master_get分別取出struct s3c24xx_spi和struct spi_master結(jié)構(gòu)指針 */ master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); if (master == NULL) { dev_err(&pdev->dev, "No memory for spi_master\n"); err = -ENOMEM; goto err_nomem; } /* 填充struct spi_master結(jié)構(gòu) */ hw = spi_master_get_devdata(master); memset(hw, 0, sizeof(struct s3c24xx_spi)); hw->master = spi_master_get(master); hw->pdata = pdev->dev.platform_data; hw->dev = &pdev->dev; if (hw->pdata == NULL) { dev_err(&pdev->dev, "No platform data supplied\n"); err = -ENOENT; goto err_no_pdata; } platform_set_drvdata(pdev, hw);//dev_set_drvdata(&pdev->dev, hw) init_completion(&hw->done); /* setup the state for the bitbang driver */ /* 填充hw->bitbang結(jié)構(gòu)(hw->bitbang結(jié)構(gòu)充當(dāng)一個(gè)中間層,相當(dāng)與input system的input_handle struct) */ hw->bitbang.master = hw->master; hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer; hw->bitbang.chipselect = s3c24xx_spi_chipsel; hw->bitbang.txrx_bufs = s3c24xx_spi_txrx; hw->bitbang.master->setup = s3c24xx_spi_setup; dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); /* find and map our resources */ /* 申請spi所用到的資源:io、irq、時(shí)鐘等 */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); err = -ENOENT; goto err_no_iores; } hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1, pdev->name); if (hw->ioarea == NULL) { dev_err(&pdev->dev, "Cannot reserve region\n"); err = -ENXIO; goto err_no_iores; } hw->regs = ioremap(res->start, (res->end - res->start)+1); if (hw->regs == NULL) { dev_err(&pdev->dev, "Cannot map IO\n"); err = -ENXIO; goto err_no_iomap; } hw->irq = platform_get_irq(pdev, 0); if (hw->irq < 0) { dev_err(&pdev->dev, "No IRQ specified\n"); err = -ENOENT; goto err_no_irq; } err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw); if (err) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); goto err_no_irq; } hw->clk = clk_get(&pdev->dev, "spi"); if (IS_ERR(hw->clk)) { dev_err(&pdev->dev, "No clock for device\n"); err = PTR_ERR(hw->clk); goto err_no_clk; } /* for the moment, permanently enable the clock */ clk_enable(hw->clk); /* program defaults into the registers */ /* 初始化spi相關(guān)的寄存器 */ writeb(0xff, hw->regs + S3C2410_SPPRE); writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); /* add by lfc */ s3c2410_gpio_setpin(S3C2410_GPE13, 0); s3c2410_gpio_setpin(S3C2410_GPE12, 0); s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0); s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0); s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0); /* end add */ /* setup any gpio we can */ /* 片選 */ if (!hw->pdata->set_cs) { s3c2410_gpio_setpin(hw->pdata->pin_cs, 1); s3c2410_gpio_cfgpin(hw->pdata->pin_cs, S3C2410_GPIO_OUTPUT); } /* register our spi controller */ /* 最終通過調(diào)用spi_register_master來注冊spi控制器(驅(qū)動(dòng)) */ err = spi_bitbang_start(&hw->bitbang); if (err) { dev_err(&pdev->dev, "Failed to register SPI master\n"); goto err_register; } dev_dbg(hw->dev, "shutdown=%d\n", hw->bitbang.shutdown); /* register all the devices associated */ /* 注冊所用使用本spi驅(qū)動(dòng)的設(shè)備 */ bi = &hw->pdata->board_info[0]; for (i = 0; i < hw->pdata->board_size; i++, bi++) { dev_info(hw->dev, "registering %s\n", bi->modalias); bi->controller_data = hw; spi_new_device(master, bi); } return 0; err_register: clk_disable(hw->clk); clk_put(hw->clk); err_no_clk: free_irq(hw->irq, hw); err_no_irq: iounmap(hw->regs); err_no_iomap: release_resource(hw->ioarea); kfree(hw->ioarea); err_no_iores: err_no_pdata: spi_master_put(hw->master);; err_nomem: return err; } 本文出自:億恩科技【mszdt.com】 服務(wù)器租用/服務(wù)器托管中國五強(qiáng)!虛擬主機(jī)域名注冊頂級提供商!15年品質(zhì)保障!--億恩科技[ENKJ.COM] |