/**************************************************************************
*本文主要跟踪imx6 spi设备和驱动的注册过程。
*
* Tony Liu, 2016-4-13, Shenzhen
*************************************************************************/ kernel/arch/arm/mach-mx6/board-mx6q_sabresd.c MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")
/* Maintainer: Freescale Semiconductor, Inc. */
.boot_params = MX6_PHYS_OFFSET + 0x100,
.fixup = fixup_mxc_board,
.map_io = mx6_map_io,
.init_irq = mx6_init_irq,
.init_machine = mx6_sabresd_board_init,
.timer = &mx6_sabresd_timer, |
.reserve = mx6q_sabresd_reserve, |
MACHINE_END |
V
static void __init mx6_sabresd_board_init(void)
{
... ...
imx6q_add_ecspi(, &mx6q_sabresd_spi_data);
imx6q_add_ecspi(, &mx6q_sabresd_spi2_data);
spi_device_init(); --------------------------------------------+
... ... | |
} | |
V |
static const struct spi_imx_master mx6q_sabresd_spi_data __initconst = { |
.chipselect = mx6q_sabresd_spi_cs, --------+ |
.num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi_cs), | |
}; | |
| |
static int mx6q_sabresd_spi_cs[] = { <--------+ |
SABRESD_ECSPI1_CS1, |
}; |
#define SABRESD_ECSPI1_CS1 IMX_GPIO_NR(3, 19) |
|
//注册平台设备 |
#define imx6q_add_ecspi(id, pdata) \ |
imx_add_spi_imx(&imx6q_ecspi_data[id], pdata) ----+ |
| |
struct platform_device *__init imx_add_spi_imx( <---+ |
const struct imx_spi_imx_data *data, |
const struct spi_imx_master *pdata) |
{ |
struct resource res[] = { |
{ |
.start = data->iobase, |
.end = data->iobase + data->iosize - , |
.flags = IORESOURCE_MEM, |
}, { |
.start = data->irq, |
.end = data->irq, |
.flags = IORESOURCE_IRQ, |
}, |
}; |
return imx_add_platform_device(data->devid, data->id, |
res, ARRAY_SIZE(res), pdata, sizeof(*pdata)); |
} |
|
static void spi_device_init(void) <------------------------+
{
spi_register_board_info(imx6_sabresd_spi_nor_device, -------------+
ARRAY_SIZE(imx6_sabresd_spi_nor_device)); |
} | |
V |
static struct spi_board_info imx6_sabresd_spi_nor_device[] __initdata = { |
#if 0 |
#if defined(CONFIG_MTD_M25P80) |
{ |
.modalias = "m25p80", |
.max_speed_hz = , /* max spi clock (SCK) speed in HZ */ |
.bus_num = , |
.chip_select = , |
.platform_data = &imx6_sabresd__spi_flash_data, |
}, |
#endif |
#endif |
{ |
.modalias = "ar1020-spi", |
.max_speed_hz = , /* max spi clock (SCK) speed in HZ */ |
.bus_num = , |
.chip_select = , |
.mode = SPI_MODE_1, |
.irq = gpio_to_irq(SABRESD_AR1020_INT), |
|
//.platform_data = &imx6_sabresd__spi_flash_data, |
}, |
|
}; |
|
int __init |
spi_register_board_info(struct spi_board_info const *info, unsigned n) <--+
{
struct boardinfo *bi;
int i; bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
if (!bi)
return -ENOMEM; for (i = ; i < n; i++, bi++, info++) {
struct spi_master *master; memcpy(&bi->board_info, info, sizeof(*info));
mutex_lock(&board_lock);
//将所有的spi设备添加到链表中
list_add_tail(&bi->list, &board_list);
list_for_each_entry(master, &spi_master_list, list)
spi_match_master_to_boardinfo(master, &bi->board_info);
mutex_unlock(&board_lock);
} return ;
} kernel/drivers/spi/spi_imx.c
static int __init spi_imx_init(void)
{
return platform_driver_register(&spi_imx_driver);
} |
V
static struct platform_driver spi_imx_driver = {
.driver = {
.name = DRIVER_NAME, // "spi_imx"
.owner = THIS_MODULE,
},
.id_table = spi_imx_devtype,
.probe = spi_imx_probe, -------+
.remove = __devexit_p(spi_imx_remove), |
}; |
V
static int __devinit spi_imx_probe(struct platform_device *pdev)
{
struct spi_imx_master *mxc_platform_info;
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
int i, ret; mxc_platform_info = dev_get_platdata(&pdev->dev);
if (!mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
return -EINVAL;
} master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
if (!master)
return -ENOMEM; platform_set_drvdata(pdev, master); master->bus_num = pdev->id;
master->num_chipselect = mxc_platform_info->num_chipselect; spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = spi_master_get(master); ---------------------+
spi_imx->chipselect = mxc_platform_info->chipselect; |
//控制spi的chipselect引脚 |
for (i = ; i < master->num_chipselect; i++) { |
if (spi_imx->chipselect[i] < ) |
continue; |
ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME); |
if (ret) { |
while (i > ) { |
i--; |
if (spi_imx->chipselect[i] >= ) |
gpio_free(spi_imx->chipselect[i]); |
} |
dev_err(&pdev->dev, "can't get cs gpios\n"); |
goto out_master_put; |
} |
} |
// spi 对应的操作函数 |
spi_imx->bitbang.chipselect = spi_imx_chipselect; |
spi_imx->bitbang.setup_transfer = spi_imx_setupxfer; |
spi_imx->bitbang.txrx_bufs = spi_imx_transfer; |
spi_imx->bitbang.master->setup = spi_imx_setup; |
spi_imx->bitbang.master->cleanup = spi_imx_cleanup; |
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; |
|
init_completion(&spi_imx->xfer_done); |
|
spi_imx->devtype_data = |
spi_imx_devtype_data[pdev->id_entry->driver_data]; |
|
res = platform_get_resource(pdev, IORESOURCE_MEM, ); |
if (!res) { |
dev_err(&pdev->dev, "can't get platform resource\n"); |
ret = -ENOMEM; |
goto out_gpio_free; |
} |
|
if (!request_mem_region(res->start, resource_size(res), pdev->name)) { |
dev_err(&pdev->dev, "request_mem_region failed\n"); |
ret = -EBUSY; |
goto out_gpio_free; |
} |
|
spi_imx->base = ioremap(res->start, resource_size(res)); |
if (!spi_imx->base) { |
ret = -EINVAL; |
goto out_release_mem; |
} |
|
spi_imx->irq = platform_get_irq(pdev, ); |
if (spi_imx->irq < ) { |
ret = -EINVAL; |
goto out_iounmap; |
} |
|
ret = request_irq(spi_imx->irq, spi_imx_isr, , DRIVER_NAME, spi_imx); |
if (ret) { |
dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret); |
goto out_iounmap; |
} |
|
spi_imx->clk = clk_get(&pdev->dev, NULL); |
if (IS_ERR(spi_imx->clk)) { |
dev_err(&pdev->dev, "unable to get clock\n"); |
ret = PTR_ERR(spi_imx->clk); |
goto out_free_irq; |
} |
|
clk_enable(spi_imx->clk); |
spi_imx->spi_clk = clk_get_rate(spi_imx->clk); |
|
spi_imx->devtype_data.reset(spi_imx); |
|
spi_imx->devtype_data.intctrl(spi_imx, ); |
ret = spi_bitbang_start(&spi_imx->bitbang); |
if (ret) { |
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret); |
goto out_clk_put; |
} |
clk_disable(spi_imx->clk); |
|
dev_info(&pdev->dev, "probed\n"); |
|
return ret; |
|
out_clk_put: |
clk_disable(spi_imx->clk); |
clk_put(spi_imx->clk); |
out_free_irq: |
free_irq(spi_imx->irq, spi_imx); |
out_iounmap: |
iounmap(spi_imx->base); |
out_release_mem: |
release_mem_region(res->start, resource_size(res)); |
out_gpio_free: |
for (i = ; i < master->num_chipselect; i++) |
if (spi_imx->chipselect[i] >= ) |
gpio_free(spi_imx->chipselect[i]); |
out_master_put: |
spi_master_put(master); |
kfree(master); |
platform_set_drvdata(pdev, NULL); |
return ret; |
} |
|
int spi_bitbang_start(struct spi_bitbang *bitbang) <-----------------+
{
int status; if (!bitbang->master || !bitbang->chipselect)
return -EINVAL; INIT_WORK(&bitbang->work, bitbang_work);
spin_lock_init(&bitbang->lock);
INIT_LIST_HEAD(&bitbang->queue); if (!bitbang->master->mode_bits)
bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags; if (!bitbang->master->transfer)
bitbang->master->transfer = spi_bitbang_transfer;
if (!bitbang->txrx_bufs) {
bitbang->use_dma = ;
bitbang->txrx_bufs = spi_bitbang_bufs;
if (!bitbang->master->setup) {
if (!bitbang->setup_transfer)
bitbang->setup_transfer =
spi_bitbang_setup_transfer;
bitbang->master->setup = spi_bitbang_setup;
bitbang->master->cleanup = spi_bitbang_cleanup;
}
} else if (!bitbang->master->setup)
return -EINVAL;
if (bitbang->master->transfer == spi_bitbang_transfer &&
!bitbang->setup_transfer)
return -EINVAL; /* this task is the only thing to touch the SPI bits */
bitbang->busy = ;
bitbang->workqueue = create_singlethread_workqueue(
dev_name(bitbang->master->dev.parent));
if (bitbang->workqueue == NULL) {
status = -EBUSY;
goto err1;
} /* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices
*/
status = spi_register_master(bitbang->master); -----+
if (status < ) |
goto err2; |
|
return status; |
|
err2: |
destroy_workqueue(bitbang->workqueue); |
err1: |
return status; |
} |
|
int spi_register_master(struct spi_master *master) <-----+
{
static atomic_t dyn_bus_id = ATOMIC_INIT((<<) - );
struct device *dev = master->dev.parent;
struct boardinfo *bi;
int status = -ENODEV;
int dynamic = ; if (!dev)
return -ENODEV; /* even if it's just one always-selected device, there must
* be at least one chipselect
*/
if (master->num_chipselect == )
return -EINVAL; /* convention: dynamically assigned bus IDs count down from the max */
if (master->bus_num < ) {
/* FIXME switch to an IDR based scheme, something like
* I2C now uses, so we can't run out of "dynamic" IDs
*/
master->bus_num = atomic_dec_return(&dyn_bus_id);
dynamic = ;
} spin_lock_init(&master->bus_lock_spinlock);
mutex_init(&master->bus_lock_mutex);
master->bus_lock_flag = ; /* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
*/
//设置设备节点的设备名 /dev/spi0, /dev/spi1
dev_set_name(&master->dev, "spi%u", master->bus_num);
status = device_add(&master->dev);
if (status < )
goto done;
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : ""); mutex_lock(&board_lock);
list_add_tail(&master->list, &spi_master_list);
list_for_each_entry(bi, &board_list, list)
spi_match_master_to_boardinfo(master, &bi->board_info);
mutex_unlock(&board_lock); status = ; /* Register devices from the device tree */
of_register_spi_devices(master);
done:
return status;
}

imx6 spi分析的更多相关文章

  1. imx6 fec分析

    /***************************************************************************** * imx6 fec分析 * 本文主要分析 ...

  2. imx6 framebuffer 分析

    分析imx6 framebuffer设备和驱动的注册过程. Tony Liu, 2016-8-31, Shenzhen 相关文件: arch/arm/mach-mx6/board-mx6q_sabre ...

  3. imx6 i2c分析

    本文主要分析: 1. i2c设备注册 2. i2c驱动注册 3. 上层调用过程参考: http://www.cnblogs.com/helloworldtoyou/p/5126618.html 1. ...

  4. imx6 MfgTool分析

    解析freescale的MfgTool中的脚本,了解imx6, android系统的分区情况. 配置文件 1. cfg.ini [profiles] chip = MX6DL Linux Update ...

  5. I2C(smbus pmbus)和SPI分析

    2C和SPI作为两种非常常用的低速外部总线 I2C I2C是以前的飞利浦半导体制定的标准,也就是如今的NXP. I2C总线由一条数据线(SDA)和一条时钟线(SCL)组成.设备分主从,主设备提供时钟, ...

  6. imx6 uart分析

    本文主要记录: 1.uart设备注册 2.uart驱动注册 3.上层应用调用有些地方理解的还不是很透彻,希望指正. 1.uart设备注册过程 MACHINE_START(MX6Q_SABRESD, & ...

  7. imx6 gpio分析

    本文主要介绍如何配置IOMUX寄存器,设置IO复用寄存器,配置为GPIO功能.参考: http://www.jianshu.com/p/3c2053508342 http://www.embest-t ...

  8. Linux SPI初始化及接口函数代码细究

    2012-01-08 22:11:38 目的:我需要掌握spi驱动相关数据结构关系,及在哪部分函数中把这些数值进行底层寄存器赋值的.结合应用层函数完成spi驱动的代码测试.已达到灵活修改的目的. 按顺 ...

  9. 02_dubbo的SPI

    [dubbo为什么不采用JDK自带的SPI] 1.JDK自带的SPI(ServiceLoader)会一次性实例化扩展点所有实现,基本只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍,如果我 ...

随机推荐

  1. cocos2dx 3.1从零学习(五)——动画

    动画是游戏中最重要的表现部分,本篇仅仅是初步学习大部分动画的用法.没有什么原理性的东西,可是样例有非常多,假设有不熟的地方要练一下. 特别是Spawn和Sequence的组合使用,什么时候使用Spaw ...

  2. Nodejs 使用 Chrome DevTools 调试 --inspect-brk

    参考链接: https://cnodejs.org/topic/5a9661ff71327bb413bbff5b https://github.com/nswbmw/node-in-debugging ...

  3. Dockerfile最佳实践(一)

    1.使用缓存  Dockerfile的每条指令都会将结果提交为新的镜像,下一跳指令将会基于上一步指令的镜像的基础上构建,如果一个镜像存在相同的父镜像和指令(除了ADD),Docker将会使用镜像而不是 ...

  4. 在 Visual Studio 2013 中使用 JavaScript 的 IntelliSense

    原本JavaScript直接在页面中引用的时候,智能感知会直接根据js文件的内容来获得提示.但是由于在新的ASP.NET中使用了Bundle,js文件不是直接在页面中引用了,所以智能感知也就出了问题. ...

  5. js中push和join方法使用介绍

    push和join方法想必大家并不陌生吧,在本文将为大家详细介绍下js中的push和join方法的使用.代码: <script type="text/javascript"& ...

  6. CentOS防火墙开启、关闭与开放指定端口

    系统为centos 5.5,部署好Tomcat之后却发现输入114.80.*.*:8080(即ip:8080)却无法显示Tomcat默认的首页.由于以前部署在Win Server的VPS上,Linux ...

  7. [k8s]如何处理dockerfile无expose情况下在k8s里暴漏访问

    做镜像时候忘记expose端口了, 或者要做一个通用的镜像, expose端口不固定, 又要在k8s环境里跑并暴漏服务访问,怎么破? 实际上: yaml的 ports: - containerPort ...

  8. wait(),notify(),notifyAll()用来操作线程为什么定义在Object类中?

    这些方法存在于同步中: 使用这些方法必须标识同步所属的锁: 锁可以是任意对象,所以任意对象调用方法一定定义在Object类中. Condition是在java 1.5中才出现的,它用来替代传统的Obj ...

  9. CocoaPods did not set the base configuration of your project 问题解决方式

    今天在使用pod install的时候.出现了 [!] CocoaPods did not set the base configuration of your project because you ...

  10. java多线程实验 滚动字

    package com.rgy.Test; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt ...