为什么我对 gpiod_set_value return 的调用会出现 "invalid GPIO" 错误?
Why do my calls to gpiod_set_value return an "invalid GPIO" error?
我正在尝试为 OV2680 相机传感器编写驱动程序。我想打开一些 GPIO 引脚作为其 ->probe()
函数中的步骤之一。这些 GpioIo() 引脚在 DSDT 表中声明如下(对于 OV2680 所依赖的设备;参见 full DSDT table:
Device (PMI1)
{
Name (_ADR, Zero) // _ADR: Address
Name (_HID, "INT3472") // _HID: Hardware ID
Name (_CID, "INT3472") // _CID: Compatible ID
Name (_DDN, "INCL-CRDD") // _DDN: DOS Device Name
Name (_UID, One) // _UID: Unique ID
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (SBUF, ResourceTemplate ()
{
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0079
}
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x007A
}
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x008F
}
})
Return (SBUF) /* \_SB_.PCI0.PMI1._CRS.SBUF */
}
}
Device (CAM1)
{
Name (_ADR, Zero) // _ADR: Address
Name (_HID, "OVTI2680") // _HID: Hardware ID
Name (_CID, "OVTI2680") // _CID: Compatible ID
Name (_DDN, "OV2680-CRDD") // _DDN: DOS Device Name
Name (_UID, One) // _UID: Unique ID
Name (_DEP, Package (0x02) // _DEP: Dependencies
{
PMI1,
I2C2
})
Name (_PLD, Package (0x01) // _PLD: Physical Location of Device
{
ToPLD (
PLD_Revision = 0x2,
PLD_IgnoreColor = 0x1,
PLD_Red = 0x0,
PLD_Green = 0x0,
PLD_Blue = 0x0,
PLD_Width = 0x0,
PLD_Height = 0x0,
PLD_UserVisible = 0x1,
PLD_Dock = 0x0,
PLD_Lid = 0x0,
PLD_Panel = "FRONT",
PLD_VerticalPosition = "CENTER",
PLD_HorizontalPosition = "RIGHT",
PLD_Shape = "VERTICALRECTANGLE",
PLD_GroupOrientation = 0x0,
PLD_GroupToken = 0x0,
PLD_GroupPosition = 0x0,
PLD_Bay = 0x0,
PLD_Ejectable = 0x1,
PLD_EjectRequired = 0x1,
PLD_CabinetNumber = 0x0,
PLD_CardCageNumber = 0x0,
PLD_Reference = 0x0,
PLD_Rotation = 0x0,
PLD_Order = 0x0,
PLD_VerticalOffset = 0xFFFF,
PLD_HorizontalOffset = 0xFFFF)
})
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (SBUF, ResourceTemplate ()
{
I2cSerialBusV2 (0x0010, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "\_SB.PCI0.I2C2",
0x00, ResourceConsumer, , Exclusive,
)
})
Return (SBUF) /* \_SB_.PCI0.CAM1._CRS.SBUF */
}
}
注意缺少 _DSD 段,这意味着我必须在驱动程序代码 according to the documentation. That's no problem; I have the struct acpi_device
for this ACPI device (by scraping the dependents of the OV2680 device that the driver matches to), so I can do that and add them with acpi_dev_add_driver_gpios()
as the documentation instructs. My question comes in the Getting GPIO Descriptor 阶段明确声明它们;文档说要使用 gpiod_get_index()
,该函数调用 struct device
而不是 struct acpi_device
。我试图通过传递 struct acpi_device::dev
成员来实现这一点,但是虽然我在这样做时没有收到任何错误消息,但当我将 GPIO 引脚设置为活动时似乎实际上没有发生任何事情,所以我不认为它正在工作。
鉴于这是特定于硬件的,我不确定 MRE 是否有用,但这里有一个应该编译并成功插入的驱动程序:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
static const struct acpi_gpio_params gpio1 = {0, 0, false};
static const struct acpi_gpio_params gpio2 = {1, 0, false};
static const struct acpi_gpio_params gpio3 = {2, 0, false};
static const struct acpi_gpio_mapping int3472_acpi_gpios[] = {
{"gpio1", &gpio1, 1},
{"gpio2", &gpio2, 1},
{"gpio3", &gpio3, 1},
{}
};
static int ov2680_probe(struct i2c_client *client)
{
/*
* The driver will match the OV2680 device, but the GPIO
* pins lie in its dependent INT3472, so we need to walk
* up the dependencies to find that device.
*/
struct acpi_device *int3472_device;
/* get ACPI handle of OV2680 device */
struct acpi_handle *dev_handle = ACPI_HANDLE(&client->dev);
/* Get dependent devices */
struct acpi_handle_list dep_devices;
acpi_evaluate_reference(dev_handle, "_DEP", NULL, &dep_devices);
int i;
for (i=0; i < dep_devices.count; i++) {
struct acpi_device_info *devinfo;
acpi_get_object_info(dep_devices.handles[i], &devinfo);
if (devinfo->valid & ACPI_VALID_HID && !strcmp(devinfo->hardware_id.string, "INT3472")) {
acpi_bus_get_device(dep_devices.handles[i], &int3472_device);
}
}
int ret;
ret = acpi_dev_add_driver_gpios(int3472_device, int3472_acpi_gpios);
struct gpio_desc *gpiod1, *gpiod2, *gpiod3;
gpiod1 = gpiod_get_index(&int3472_device->dev, NULL, 0, GPIOD_ASIS);
gpiod2 = gpiod_get_index(&int3472_device->dev, NULL, 1, GPIOD_ASIS);
gpiod3 = gpiod_get_index(&int3472_device->dev, NULL, 2, GPIOD_ASIS);
gpiod_set_value_cansleep(gpiod1, 1);
gpiod_set_value_cansleep(gpiod2, 1);
gpiod_set_value_cansleep(gpiod3, 1);
return 0;
}
static int ov2680_remove(struct i2c_client *client)
{
/*
* Code goes here to get acpi_device, turn off all
* the GPIO pins, remove them from the ACPI device
* and whatnot
*/
return 0;
}
static const struct acpi_device_id ov2680_acpi_match[] = {
{"OVTI2680", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match);
static struct i2c_driver ov2680_driver = {
.driver = {
.name = "ov2680",
.acpi_match_table = ov2680_acpi_match,
},
.probe_new = ov2680_probe,
.remove = ov2680_remove,
};
module_i2c_driver(ov2680_driver);
MODULE_AUTHOR("Dan Scally");
MODULE_DESCRIPTION("A driver for OmniVision 2680 sensors");
MODULE_LICENSE("GPL");
dmesg
报告在添加引脚或任何东西时没有问题,但是对 gpiod_set_value_cansleep()
的调用在那里抛出错误:
[4840.774633] gpiod_set_value_cansleep: invalid GPIO (errorpointer)
这显然是因为对 gpiod_get_index()
的调用失败,因此 GPIO 描述符无效。
问题:
- 我使用
&int3472->device
作为 gpiod_get_index()
的参数是正确的方法吗?
- 如果是这样,什么可能导致对
gpiod_get_index()
的调用失败?
编辑:
grep -H 15 /sys/bus/acpi/devices/*/status
的输出
/sys/bus/acpi/devices/ACPI000C:00/status:15
/sys/bus/acpi/devices/BOSC0200:00/status:15
/sys/bus/acpi/devices/device:16/status:15
/sys/bus/acpi/devices/device:17/status:15
/sys/bus/acpi/devices/device:32/status:15
/sys/bus/acpi/devices/INT33D3:00/status:15
/sys/bus/acpi/devices/INT33D6:00/status:15
/sys/bus/acpi/devices/INT3400:00/status:15
/sys/bus/acpi/devices/INT340E:00/status:15
/sys/bus/acpi/devices/INT344B:00/status:15
/sys/bus/acpi/devices/INT3472:08/status:15
/sys/bus/acpi/devices/INT3472:09/status:15
/sys/bus/acpi/devices/INT3F0D:00/status:15
/sys/bus/acpi/devices/MSFT0001:00/status:15
/sys/bus/acpi/devices/MSFT0101:00/status:15
/sys/bus/acpi/devices/OVTI2680:00/status:15
/sys/bus/acpi/devices/OVTI5648:00/status:15
/sys/bus/acpi/devices/PNP0103:00/status:15
/sys/bus/acpi/devices/PNP0401:01/status:15
/sys/bus/acpi/devices/PNP0A05:04/status:15
/sys/bus/acpi/devices/PNP0C09:00/status:15
/sys/bus/acpi/devices/PNP0C0C:00/status:15
/sys/bus/acpi/devices/PNP0C0D:00/status:15
/sys/bus/acpi/devices/VPC2004:00/status:15
/sys/bus/acpi/devices/WCOM508C:00/status:15
(根据我之前给出的评论收集答案)
为了澄清起见,我不得不说,从您的 DSDT 我们可以得到以下信息。有3组PMIC,即DSCx
、CLPx
和PMIx
。我相信它们基于模型,例如 Desktop、Laptop、2-in-1。在每种情况下,同一组中的所有 PMIC 都具有不同的 _UID
。从 grep -H 15 ...
提供的输出中,我们只有十分之二的实例 INT3472:08 和 INT3472:09(正好是 DSDT 中最后定义的两个)。他们是PMIx
,你可以通过grep -H . /sys/bus/acpi/devices/INT3472:*/path
查看。
您感兴趣的是 PMI1
,它 消耗 来自 Intel GPIO driver, i.e. pins 121, 122 and 143 (you may decode them as Community #2, Group #5 or GPP_F, relative to the group pins 1, 2 and 23, this may help you to understand _INI
method that touches these lines via other methods in DSDT), and provides 3 + 7 = 10 pins according to its driver 的三个 GPIO 线。
现在到代码。 _DEP
ACPI 方法仅用于链接电源资源,而 Linux 内核有其他方法如何从其他设备劫持资源,因为您要做的是使用不相关的资源到您为其创建驱动程序的设备。
方法是通过ACPI HID查找设备:
struct acpi_device *adev;
struct device *phys_dev;
struct gpio_desc *desc;
...
adev = acpi_dev_get_first_match_dev("INT3472", "1", -1);
if (!adev) {
pr_err("Oops, we didn't find an ACPI device!\n");
return -ENODEV;
}
phys_dev = get_device(acpi_get_first_physical_node(adev));
acpi_dev_put(adev);
if (!phys_dev) {
pr_err("Oops, we didn't find a physical device!\n");
return -ENODEV;
}
desc = gpiod_get_index(phys_dev, NULL, 0, GPIOD_ASIS);
if (IS_ERR(desc)) {
pr_err("Something went wrong when retrieving GPIO\n");
put_device(phys_dev);
return PTR_ERR(desc);
}
...
gpiod_put(desc);
put_device(phys_dev);
Hackish 的简化方法(因为您知道总线类型和设备实例的确切名称,但 Linux 不保证它在启动时保持相同)是:
struct device *phys_dev;
struct gpio_desc *desc;
...
phys_dev = bus_find_device_by_name(&i2c_bus_type, NULL, "i2c-INT3472:09");
if (!phys_dev) {
pr_err("Oops, we didn't find a physical device!\n");
return -ENODEV;
}
desc = gpiod_get_index(phys_dev, NULL, 0, GPIOD_ASIS);
if (IS_ERR(desc)) {
pr_err("Something went wrong when retrieving GPIO\n");
put_device(phys_dev);
return PTR_ERR(desc);
}
...
gpiod_put(desc);
put_device(phys_dev);
旁注:
- OV2680 相机传感器已经 existing driver,扩展它而不是为 ACPI 案例创建特定的分支是有意义的。
- 正确的方法是在没有任何黑客攻击的情况下使用资源,即在 PMIC MFD driver。
我正在尝试为 OV2680 相机传感器编写驱动程序。我想打开一些 GPIO 引脚作为其 ->probe()
函数中的步骤之一。这些 GpioIo() 引脚在 DSDT 表中声明如下(对于 OV2680 所依赖的设备;参见 full DSDT table:
Device (PMI1)
{
Name (_ADR, Zero) // _ADR: Address
Name (_HID, "INT3472") // _HID: Hardware ID
Name (_CID, "INT3472") // _CID: Compatible ID
Name (_DDN, "INCL-CRDD") // _DDN: DOS Device Name
Name (_UID, One) // _UID: Unique ID
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (SBUF, ResourceTemplate ()
{
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0079
}
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x007A
}
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x008F
}
})
Return (SBUF) /* \_SB_.PCI0.PMI1._CRS.SBUF */
}
}
Device (CAM1)
{
Name (_ADR, Zero) // _ADR: Address
Name (_HID, "OVTI2680") // _HID: Hardware ID
Name (_CID, "OVTI2680") // _CID: Compatible ID
Name (_DDN, "OV2680-CRDD") // _DDN: DOS Device Name
Name (_UID, One) // _UID: Unique ID
Name (_DEP, Package (0x02) // _DEP: Dependencies
{
PMI1,
I2C2
})
Name (_PLD, Package (0x01) // _PLD: Physical Location of Device
{
ToPLD (
PLD_Revision = 0x2,
PLD_IgnoreColor = 0x1,
PLD_Red = 0x0,
PLD_Green = 0x0,
PLD_Blue = 0x0,
PLD_Width = 0x0,
PLD_Height = 0x0,
PLD_UserVisible = 0x1,
PLD_Dock = 0x0,
PLD_Lid = 0x0,
PLD_Panel = "FRONT",
PLD_VerticalPosition = "CENTER",
PLD_HorizontalPosition = "RIGHT",
PLD_Shape = "VERTICALRECTANGLE",
PLD_GroupOrientation = 0x0,
PLD_GroupToken = 0x0,
PLD_GroupPosition = 0x0,
PLD_Bay = 0x0,
PLD_Ejectable = 0x1,
PLD_EjectRequired = 0x1,
PLD_CabinetNumber = 0x0,
PLD_CardCageNumber = 0x0,
PLD_Reference = 0x0,
PLD_Rotation = 0x0,
PLD_Order = 0x0,
PLD_VerticalOffset = 0xFFFF,
PLD_HorizontalOffset = 0xFFFF)
})
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (SBUF, ResourceTemplate ()
{
I2cSerialBusV2 (0x0010, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "\_SB.PCI0.I2C2",
0x00, ResourceConsumer, , Exclusive,
)
})
Return (SBUF) /* \_SB_.PCI0.CAM1._CRS.SBUF */
}
}
注意缺少 _DSD 段,这意味着我必须在驱动程序代码 according to the documentation. That's no problem; I have the struct acpi_device
for this ACPI device (by scraping the dependents of the OV2680 device that the driver matches to), so I can do that and add them with acpi_dev_add_driver_gpios()
as the documentation instructs. My question comes in the Getting GPIO Descriptor 阶段明确声明它们;文档说要使用 gpiod_get_index()
,该函数调用 struct device
而不是 struct acpi_device
。我试图通过传递 struct acpi_device::dev
成员来实现这一点,但是虽然我在这样做时没有收到任何错误消息,但当我将 GPIO 引脚设置为活动时似乎实际上没有发生任何事情,所以我不认为它正在工作。
鉴于这是特定于硬件的,我不确定 MRE 是否有用,但这里有一个应该编译并成功插入的驱动程序:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
static const struct acpi_gpio_params gpio1 = {0, 0, false};
static const struct acpi_gpio_params gpio2 = {1, 0, false};
static const struct acpi_gpio_params gpio3 = {2, 0, false};
static const struct acpi_gpio_mapping int3472_acpi_gpios[] = {
{"gpio1", &gpio1, 1},
{"gpio2", &gpio2, 1},
{"gpio3", &gpio3, 1},
{}
};
static int ov2680_probe(struct i2c_client *client)
{
/*
* The driver will match the OV2680 device, but the GPIO
* pins lie in its dependent INT3472, so we need to walk
* up the dependencies to find that device.
*/
struct acpi_device *int3472_device;
/* get ACPI handle of OV2680 device */
struct acpi_handle *dev_handle = ACPI_HANDLE(&client->dev);
/* Get dependent devices */
struct acpi_handle_list dep_devices;
acpi_evaluate_reference(dev_handle, "_DEP", NULL, &dep_devices);
int i;
for (i=0; i < dep_devices.count; i++) {
struct acpi_device_info *devinfo;
acpi_get_object_info(dep_devices.handles[i], &devinfo);
if (devinfo->valid & ACPI_VALID_HID && !strcmp(devinfo->hardware_id.string, "INT3472")) {
acpi_bus_get_device(dep_devices.handles[i], &int3472_device);
}
}
int ret;
ret = acpi_dev_add_driver_gpios(int3472_device, int3472_acpi_gpios);
struct gpio_desc *gpiod1, *gpiod2, *gpiod3;
gpiod1 = gpiod_get_index(&int3472_device->dev, NULL, 0, GPIOD_ASIS);
gpiod2 = gpiod_get_index(&int3472_device->dev, NULL, 1, GPIOD_ASIS);
gpiod3 = gpiod_get_index(&int3472_device->dev, NULL, 2, GPIOD_ASIS);
gpiod_set_value_cansleep(gpiod1, 1);
gpiod_set_value_cansleep(gpiod2, 1);
gpiod_set_value_cansleep(gpiod3, 1);
return 0;
}
static int ov2680_remove(struct i2c_client *client)
{
/*
* Code goes here to get acpi_device, turn off all
* the GPIO pins, remove them from the ACPI device
* and whatnot
*/
return 0;
}
static const struct acpi_device_id ov2680_acpi_match[] = {
{"OVTI2680", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match);
static struct i2c_driver ov2680_driver = {
.driver = {
.name = "ov2680",
.acpi_match_table = ov2680_acpi_match,
},
.probe_new = ov2680_probe,
.remove = ov2680_remove,
};
module_i2c_driver(ov2680_driver);
MODULE_AUTHOR("Dan Scally");
MODULE_DESCRIPTION("A driver for OmniVision 2680 sensors");
MODULE_LICENSE("GPL");
dmesg
报告在添加引脚或任何东西时没有问题,但是对 gpiod_set_value_cansleep()
的调用在那里抛出错误:
[4840.774633] gpiod_set_value_cansleep: invalid GPIO (errorpointer)
这显然是因为对 gpiod_get_index()
的调用失败,因此 GPIO 描述符无效。
问题:
- 我使用
&int3472->device
作为gpiod_get_index()
的参数是正确的方法吗? - 如果是这样,什么可能导致对
gpiod_get_index()
的调用失败?
编辑:
grep -H 15 /sys/bus/acpi/devices/*/status
/sys/bus/acpi/devices/ACPI000C:00/status:15
/sys/bus/acpi/devices/BOSC0200:00/status:15
/sys/bus/acpi/devices/device:16/status:15
/sys/bus/acpi/devices/device:17/status:15
/sys/bus/acpi/devices/device:32/status:15
/sys/bus/acpi/devices/INT33D3:00/status:15
/sys/bus/acpi/devices/INT33D6:00/status:15
/sys/bus/acpi/devices/INT3400:00/status:15
/sys/bus/acpi/devices/INT340E:00/status:15
/sys/bus/acpi/devices/INT344B:00/status:15
/sys/bus/acpi/devices/INT3472:08/status:15
/sys/bus/acpi/devices/INT3472:09/status:15
/sys/bus/acpi/devices/INT3F0D:00/status:15
/sys/bus/acpi/devices/MSFT0001:00/status:15
/sys/bus/acpi/devices/MSFT0101:00/status:15
/sys/bus/acpi/devices/OVTI2680:00/status:15
/sys/bus/acpi/devices/OVTI5648:00/status:15
/sys/bus/acpi/devices/PNP0103:00/status:15
/sys/bus/acpi/devices/PNP0401:01/status:15
/sys/bus/acpi/devices/PNP0A05:04/status:15
/sys/bus/acpi/devices/PNP0C09:00/status:15
/sys/bus/acpi/devices/PNP0C0C:00/status:15
/sys/bus/acpi/devices/PNP0C0D:00/status:15
/sys/bus/acpi/devices/VPC2004:00/status:15
/sys/bus/acpi/devices/WCOM508C:00/status:15
(根据我之前给出的评论收集答案)
为了澄清起见,我不得不说,从您的 DSDT 我们可以得到以下信息。有3组PMIC,即DSCx
、CLPx
和PMIx
。我相信它们基于模型,例如 Desktop、Laptop、2-in-1。在每种情况下,同一组中的所有 PMIC 都具有不同的 _UID
。从 grep -H 15 ...
提供的输出中,我们只有十分之二的实例 INT3472:08 和 INT3472:09(正好是 DSDT 中最后定义的两个)。他们是PMIx
,你可以通过grep -H . /sys/bus/acpi/devices/INT3472:*/path
查看。
您感兴趣的是 PMI1
,它 消耗 来自 Intel GPIO driver, i.e. pins 121, 122 and 143 (you may decode them as Community #2, Group #5 or GPP_F, relative to the group pins 1, 2 and 23, this may help you to understand _INI
method that touches these lines via other methods in DSDT), and provides 3 + 7 = 10 pins according to its driver 的三个 GPIO 线。
现在到代码。 _DEP
ACPI 方法仅用于链接电源资源,而 Linux 内核有其他方法如何从其他设备劫持资源,因为您要做的是使用不相关的资源到您为其创建驱动程序的设备。
方法是通过ACPI HID查找设备:
struct acpi_device *adev;
struct device *phys_dev;
struct gpio_desc *desc;
...
adev = acpi_dev_get_first_match_dev("INT3472", "1", -1);
if (!adev) {
pr_err("Oops, we didn't find an ACPI device!\n");
return -ENODEV;
}
phys_dev = get_device(acpi_get_first_physical_node(adev));
acpi_dev_put(adev);
if (!phys_dev) {
pr_err("Oops, we didn't find a physical device!\n");
return -ENODEV;
}
desc = gpiod_get_index(phys_dev, NULL, 0, GPIOD_ASIS);
if (IS_ERR(desc)) {
pr_err("Something went wrong when retrieving GPIO\n");
put_device(phys_dev);
return PTR_ERR(desc);
}
...
gpiod_put(desc);
put_device(phys_dev);
Hackish 的简化方法(因为您知道总线类型和设备实例的确切名称,但 Linux 不保证它在启动时保持相同)是:
struct device *phys_dev;
struct gpio_desc *desc;
...
phys_dev = bus_find_device_by_name(&i2c_bus_type, NULL, "i2c-INT3472:09");
if (!phys_dev) {
pr_err("Oops, we didn't find a physical device!\n");
return -ENODEV;
}
desc = gpiod_get_index(phys_dev, NULL, 0, GPIOD_ASIS);
if (IS_ERR(desc)) {
pr_err("Something went wrong when retrieving GPIO\n");
put_device(phys_dev);
return PTR_ERR(desc);
}
...
gpiod_put(desc);
put_device(phys_dev);
旁注:
- OV2680 相机传感器已经 existing driver,扩展它而不是为 ACPI 案例创建特定的分支是有意义的。
- 正确的方法是在没有任何黑客攻击的情况下使用资源,即在 PMIC MFD driver。