MTK平台dts里添加中断pin
在MTK dts里配置中断pin,有两种方式
一、驱动内申请中断
这种方式比较通用,dts配置pin脚为gpio mode,在驱动内通过API申请中断。
例如使用GPIO7作为芯片中断
- dts内配置节点:
test: test@41 {
compatible = "test";
reg = <0x41>; /* x41 for HW */
pinctrl-names = "default";
pinctrl-0 = <&irq_default>;
irq-gpios = <&pio 7 GPIO_ACTIVE_LOW>;
};
- 配置gpio7的pinctrl设置为输入,内部上拉
irq_default: irqdefault {
d_pin_irq: pin_irq {
pinmux = <PINMUX_GPIO7__FUNC_GPIO7>;
input-enable;
bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
};
};
- 驱动内解析gpio并使用API申请中断
struct gpio_desc *irq_gpiopin;
int irq;
/* Setup irq if gpio is provided */
irq_gpiopin = devm_gpiod_get(card->dev, "irq", GPIOD_IN);
/*获取中断号*/
irq = gpiod_to_irq(irq_gpiopin);
/*申请下降沿中断
并注册中断回调函数irq_callback_func*/
ret = request_irq(irq, irq_callback_func,
IRQF_TRIGGER_FALLING, "irq-eint", dev);
在中断回调函数内加入自己的逻辑即可。
二、dts内指定中断
这个方式适用于platform device、spi device、i2c device,中断资源会在解析设备树dtb时进行解析并申请,保存申请的中断号。
2.1 对于platform_device
一个节点能被转换为platform_device,如果它的设备树里指定了中断属性,那么可以从platform_device中获得“中断资源”,函数如下,可以使用下列函数获得IORESOURCE_IRQ资源,即中断号:
struct resource *platform_get_resource(struct platform_device *dev,
unsigned int type, unsigned int num);
2.2 对于i2c device
dts配置
test: test@41 {
compatible = "test";
reg = <0x41>; /* x41 for HW */
pinctrl-names = "default";
pinctrl-0 = <&irq_default>;
interrupt-parent = <&pio>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>; //指定gpio7 下降沿中断
};
i2c-core-base.c内,在i2c bus对i2c device和i2c driver进行match后,进行i2c_device_probe,此时解析i2c device node
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
int status;
if (!client)
return 0;
driver = to_i2c_driver(dev->driver);
if (!client->irq && !driver->disable_i2c_core_irq_mapping) {
int irq = -ENOENT;
if (client->flags & I2C_CLIENT_HOST_NOTIFY) {
dev_dbg(dev, "Using Host Notify IRQ\n");
/* Keep adapter active when Host Notify is required */
pm_runtime_get_sync(&client->adapter->dev);
irq = i2c_smbus_host_notify_to_irq(client);
} else if (dev->of_node) {
irq = of_irq_get_byname(dev->of_node, "irq");
if (irq == -EINVAL || irq == -ENODATA)
irq = of_irq_get(dev->of_node, 0);//解析dts内interrupt相关信息并返回linux内核中断号
} else if (ACPI_COMPANION(dev)) {
irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
}
if (irq == -EPROBE_DEFER)
return irq;
if (irq < 0)
irq = 0;
client->irq = irq;//保存至client->irq
}
/**
* of_irq_get - Decode a node's IRQ and return it as a Linux IRQ number
* @dev: pointer to device tree node
* @index: zero-based index of the IRQ
*
* Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
* -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
* of any other failure.
*/
int of_irq_get(struct device_node *dev, int index)
{
int rc;
struct of_phandle_args oirq;
struct irq_domain *domain;
rc = of_irq_parse_one(dev, index, &oirq);
if (rc)
return rc;
domain = irq_find_host(oirq.np);
if (!domain)
return -EPROBE_DEFER;
return irq_create_of_mapping(&oirq);
}
EXPORT_SYMBOL_GPL(of_irq_get);
在驱动代码里直接使用,申请中断处理函数irq_handler
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev,
client->irq,
NULL,
irq_handler,
IRQF_ONESHOT | IRQF_SHARED,
dev_name(&client->dev), data);
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
client->irq);
return ret;
}