通常我们会在与I2C适配器所对应的platform_driver的probe() 函数中完成两个工作。
·初始化I2C适配器所使用的硬件资源, 如申请I/O地址、 中断号、 时钟等。
·通过i2c_add_adapter() 添加i2c_adapter的数据结构, 当然这个i2c_adapter数据结构的成员已经被xxx
适配器的相应函数指针所初始化。
static int altr_i2c_probe(struct platform_device *pdev) { struct altr_i2c_dev *idev = NULL; int irq, ret; idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL); if (!idev) return -ENOMEM; idev->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(idev->base)) return PTR_ERR(idev->base); irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; idev->i2c_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(idev->i2c_clk)) { dev_err(&pdev->dev, "missing clock\n"); return PTR_ERR(idev->i2c_clk); } idev->dev = &pdev->dev; init_completion(&idev->msg_complete); mutex_init(&idev->isr_mutex); ret = device_property_read_u32(idev->dev, "fifo-size", &idev->fifo_size); if (ret) { dev_err(&pdev->dev, "FIFO size set to default of %d\n", ALTR_I2C_DFLT_FIFO_SZ); idev->fifo_size = ALTR_I2C_DFLT_FIFO_SZ; } ret = device_property_read_u32(idev->dev, "clock-frequency", &idev->bus_clk_rate); if (ret) { dev_err(&pdev->dev, "Default to 100kHz\n"); idev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; /* default clock rate */ } if (idev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ) { dev_err(&pdev->dev, "invalid clock-frequency %d\n", idev->bus_clk_rate); return -EINVAL; } ret = devm_request_threaded_irq(&pdev->dev, irq, altr_i2c_isr_quick, altr_i2c_isr, IRQF_ONESHOT, pdev->name, idev); if (ret) { dev_err(&pdev->dev, "failed to claim IRQ %d\n", irq); return ret; } ret = clk_prepare_enable(idev->i2c_clk); if (ret) { dev_err(&pdev->dev, "failed to enable clock\n"); return ret; } mutex_lock(&idev->isr_mutex); altr_i2c_init(idev); mutex_unlock(&idev->isr_mutex); i2c_set_adapdata(&idev->adapter, idev); strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); idev->adapter.owner = THIS_MODULE; idev->adapter.algo = &altr_i2c_algo; idev->adapter.dev.parent = &pdev->dev; idev->adapter.dev.of_node = pdev->dev.of_node; platform_set_drvdata(pdev, idev); ret = i2c_add_adapter(&idev->adapter); if (ret) { clk_disable_unprepare(idev->i2c_clk); return ret; } dev_info(&pdev->dev, "Altera SoftIP I2C Probe Complete\n"); return 0; } |
通常我们会在platform_driver的remove() 函数中完成与加载函数相反的工作。
·释放I2C适配器所使用的硬件资源, 如释放I/O地址、 中断号、 时钟等。
·通过i2c_del_adapter() 删除i2c_adapter的数据结构。
static int altr_i2c_remove(struct platform_device *pdev) { struct altr_i2c_dev *idev = platform_get_drvdata(pdev); clk_disable_unprepare(idev->i2c_clk); i2c_del_adapter(&idev->adapter); return 0; } |
static const struct of_device_id altr_i2c_of_match[] = { { .compatible = "altr,softip-i2c-v1.0" }, {}, }; MODULE_DEVICE_TABLE(of, altr_i2c_of_match); static struct platform_driver altr_i2c_driver = { .probe = altr_i2c_probe, .remove = altr_i2c_remove, .driver = { .name = "altera-i2c", .of_match_table = altr_i2c_of_match, }, }; |