在嵌入式系統開發中,Linux裝置驅動程式扮演著關鍵角色,特別是對於需要精確控制硬體的應用來說,中斷處理和PWM控制更是不可或缺的技術。本文以CY8C9520A這款GPIO擴充套件晶片為例,深入剖析如何在Linux驅動程式中實作這兩項功能。CY8C9520A透過I2C介面與主控器通訊,驅動程式需要妥善處理I2C通訊流程,並正確組態裝置樹以確保硬體正常運作。此外,Pin Control子系統的整合也是驅動程式開發的重點,它能提供更靈活的GPIO組態選項,讓開發者能更有效地控制硬體資源。
探討Linux裝置驅動程式中的中斷處理與PWM控制
在Linux裝置驅動程式開發中,中斷處理與PWM(Pulse Width Modulation)控制是兩個極為重要的主題。本篇文章將探討如何在裝置驅動程式中實作中斷處理以及PWM控制,並以CY8C9520A裝置為例,詳細解析相關的程式碼實作和裝置樹組態。
中斷處理在裝置驅動程式中的重要性
中斷處理是裝置驅動程式中不可或缺的一部分,它使得系統能夠及時回應硬體事件,提高系統的即時性和效率。在CY8C9520A裝置驅動程式中,中斷處理的實作涉及到裝置樹的組態和相關的回呼函式。
裝置樹組態
首先,我們需要在裝置樹中組態中斷相關的屬性。以下是一個範例組態:
cy8c9520a: cy8c9520a@20 {
compatible = "cy8c9520a";
reg = <0x20>;
interrupt-controller;
#interrupt-cells = <2>;
gpio-controller;
#gpio-cells = <2>;
interrupts = <23 1>;
interrupt-parent = <&gpio>;
pinctrl-names = "default";
pinctrl-0 = <&accel_int_pin &cy8c9520apullups &cy8c9520apulldowns &cy8c9520adrivestrength>;
cy8c9520apullups: pinmux1 {
pins = "gpio0", "gpio1";
bias-pull-up;
};
cy8c9520apulldowns: pinmux2 {
pins = "gpio2";
bias-pull-down;
};
cy8c9520adrivestrength: pinmux3 {
pins = "gpio3";
drive-strength;
};
};
accel_int_pin: accel_int_pin {
brcm,pins = <23>;
brcm,function = <0>; /* Input */
brcm,pull = <0>; /* none */
};
程式碼實作
在CY8C9520A裝置驅動程式中,我們需要實作cygpio_pinconf_set回呼函式來組態引腳的驅動模式。以下是該函式的範例程式碼:
static int cygpio_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, unsigned int num_configs)
{
struct cy8c9520a *cygpio = pinctrl_dev_get_drvdata(pctldev);
struct i2c_client *client = cygpio->client;
enum pin_config_param param;
u32 arg;
int ret = 0;
int i;
u8 offs = 0;
u8 val = 0;
u8 port = cypress_get_port(pin);
u8 pin_offset = cypress_get_offs(pin, port);
mutex_lock(&cygpio->lock);
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
offs = 0x0;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
offs = 0x01;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
offs = 0x04;
break;
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
offs = 0x06;
break;
default:
dev_err(&client->dev, "Invalid config param %04x\n", param);
return -ENOTSUPP;
}
i2c_smbus_write_byte_data(client, REG_PORT_SELECT, port);
ret = i2c_smbus_read_byte_data(client, REG_DRIVE_PULLUP + offs);
val = (u8)(ret | BIT(pin_offset));
i2c_smbus_write_byte_data(client, REG_DRIVE_PULLUP + offs, val);
}
mutex_unlock(&cygpio->lock);
return ret;
}
詳細解說
cygpio_pinconf_set函式:該函式負責根據傳入的組態引數設定CY8C9520A裝置的引腳組態。- 引數解析:函式透過
pinconf_to_config_param和pinconf_to_config_argument解析傳入的組態引數,確定需要執行的組態操作。 - I2C操作:函式透過I2C介面與CY8C9520A裝置進行通訊,寫入相應的暫存器以完成引腳組態。
- 互斥鎖保護:使用互斥鎖確保在多執行緒環境下對裝置的存取是安全的。
PWM控制在CY8C9520A裝置中的實作
CY8C9520A裝置支援PWM(Pulse Width Modulation)功能,Linux核心提供了一套PWM框架來簡化PWM控制器的實作。
PWM控制器驅動程式實作
首先,需要初始化pwm_chip結構體,該結構體定義了PWM控制器的屬性和操作方法:
cygpio->pwm_chip.dev = &client->dev;
cygpio->pwm_chip.ops = &cy8c9520a_pwm_ops;
cygpio->pwm_chip.base = PWM_BASE_ID;
cygpio->pwm_chip.npwm = NPWM;
其中,cy8c9520a_pwm_ops結構體包含了PWM通道的操作方法:
static const struct pwm_ops cy8c9520a_pwm_ops = {
.request = cy8c9520a_pwm_request,
.config = cy8c9520a_pwm_config,
.enable = cy8c9520a_pwm_enable,
.disable = cy8c9520a_pwm_disable,
};
詳細解說
cy8c9520a_pwm_ops結構體:定義了PWM通道的操作方法,包括請求、組態、啟用和停用PWM通道。cygpio->pwm_chip初始化:設定了PWM控制器的裝置、操作方法、基址和PWM通道數量等屬性。- 裝置樹組態:需要在裝置樹中新增PWM相關的組態,例如:
#pwm-cells = <2>; pwm0 = <20>; // pwm not supported pwm1 = <3>; pwm2 = <20>; // pwm not supported pwm3 = <2>;
## CY8C9520A 驅動程式開發:處理中斷與 PWM 控制
在 Linux 驅動程式開發中,處理硬體中斷和 PWM(脈寬調變)控制是重要的課題。本文將探討如何在 CY8C9520A 驅動程式中處理中斷,並實作 PWM 控制功能。
### 硬體概述與驅動程式架構
CY8C9520A 是一款由 Cypress(現為 Infineon 旗下)生產的 I2C 介面 GPIO 擴充套件晶片,支援多個 GPIO 腳位和 PWM 功能。該晶片廣泛應用於嵌入式系統和物聯網裝置中,用於擴充套件主控器的 GPIO 功能。
#### 驅動程式主要結構
驅動程式的核心結構 `struct cy8c9520a` 包含多個重要成員:
```c
struct cy8c9520a {
struct i2c_client *client;
struct gpio_chip gpio_chip;
struct irq_chip irq_chip;
struct pwm_chip pwm_chip;
// 其他成員...
};
這些成員分別對應 I2C 使用者端、GPIO 控制、IRQ(中斷請求)處理和 PWM 控制等功能。
中斷處理實作
CY8C9520A 支援中斷功能,可用於檢測 GPIO 狀態變化。在驅動程式中,中斷處理需要以下步驟:
註冊中斷處理函式
- 使用
request_threaded_irq函式註冊中斷處理函式。 - 中斷處理函式負責讀取中斷狀態暫存器,並根據需要觸發對應的事件。
- 使用
組態中斷遮罩
- 使用
device_property_read_u32函式讀取裝置樹中的中斷組態。 - 設定中斷遮罩暫存器,啟用或停用特定 GPIO 的中斷功能。
- 使用
程式碼範例:中斷處理函式
static irqreturn_t cy8c9520a_irq_handler(int irq, void *data)
{
struct cy8c9520a *cygpio = data;
// 讀取中斷狀態並處理
// ...
return IRQ_HANDLED;
}
內容解密:
cy8c9520a_irq_handler是中斷處理函式,當 CY8C9520A 發生中斷時被呼叫。- 該函式接收兩個引數:
irq(中斷號)和data(指向struct cy8c9520a結構的指標)。 - 在函式內部,讀取 CY8C9520A 的中斷狀態暫存器,以確定觸發中斷的 GPIO 腳位。
- 根據中斷來源執行對應的處理邏輯,例如通知應用層或執行其他必要的操作。
PWM 控制實作
CY8C9520A 支援多個 PWM 通道,可用於控制 LED 亮度、馬達速度等應用。PWM 控制涉及以下步驟:
解析裝置樹組態
- 從裝置樹讀取 PWM 通道的組態,包括對應的 GPIO 腳位和 PWM 引數。
初始化 PWM 晶片
- 使用
pwmchip_add函式註冊 PWM 晶片。 - 組態 PWM 時鐘源和預分頻器,以設定 PWM 的基本頻率。
- 使用
程式碼範例:PWM 組態
/* parse the DT to get the pwm-pin mapping */
for (i = 0; i < NPWM; i++) {
ret = device_property_read_u32(&client->dev, name[i], &tmp);
if (!ret)
cygpio->pwm_number[i] = tmp;
else
goto err;
};
內容解密:
- 此段程式碼遍歷所有 PWM 通道(數量由
NPWM定義),從裝置樹讀取對應的組態資訊。 - 使用
device_property_read_u32從裝置樹讀取特定屬性值,並將其儲存到cygpio->pwm_number[i]中。 - 如果讀取失敗(
ret != 0),則跳轉到錯誤處理標籤err。
Pin Control 子系統整合
CY8C9520A 驅動程式還需要與 Linux 的 Pin Control 子系統整合,以支援更靈活的 GPIO 組態。驅動程式實作了 pinctrl_ops 結構體,以提供 Pin Control 相關的操作介面。
程式碼範例:Pin Control 操作
static const struct pinctrl_ops cygpio_pinctrl_ops = {
.get_groups_count = cygpio_pinctrl_get_groups_count,
.get_group_name = cygpio_pinctrl_get_group_name,
.get_group_pins = cygpio_pinctrl_get_group_pins,
// 其他操作...
};
內容解密:
cygpio_pinctrl_ops定義了 Pin Control 子系統的操作介面。.get_groups_count、get_group_name和.get_group_pins分別用於取得群組數量、群組名稱和群組中的 Pin。- 這些操作介面使驅動程式能夠與 Linux 的 Pin Control 子系統無縫整合,提供更靈活的 GPIO 組態選項。
裝置驅動程式中的中斷處理(七)- Cypress CY8C9520A GPIO 驅動分析
在 Linux 核心中,裝置驅動程式扮演著硬體與作業系統之間的橋樑角色。其中,GPIO(通用輸入/輸出)驅動程式是常見的一種,用於控制裝置的輸入輸出操作。本文將探討 Cypress CY8C9520A 這款 GPIO 擴充套件晶片的驅動程式實作,特別是在中斷處理方面的相關內容。
CY8C9520A 驅動架構
CY8C9520A 是一款透過 I2C 介面擴充套件 GPIO 的裝置,其驅動程式主要涉及以下幾個關鍵部分:
- Pin Control 架構整合:驅動程式實作了 Linux Pin Control 子系統的相關介面,使得 CY8C9520A 的 GPIO 可以被靈活地組態和管理。
- GPIO 操作實作:提供了
struct gpio_chip結構體所需的回呼函式,用於實作 GPIO 的基本操作,如讀取輸入值、設定輸出值以及組態方向等。 - I2C 通訊處理:由於 CY8C9520A 是透過 I2C 介面與主控器通訊,驅動程式中使用了 I2C 相關的 API(如
i2c_smbus_read_byte_data和i2c_smbus_write_byte_data)來進行資料傳輸。
Pin Configuration 操作實作
驅動程式中的 cygpio_pinconf_set 函式負責處理 Pin Configuration 的設定請求。該函式會根據傳入的引數來組態指定的 GPIO Pin,例如設定上拉/下拉電阻、驅動強度等。
static int cygpio_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, unsigned int num_configs)
{
// ...
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
// 設定上拉電阻
offs = 0x0;
dev_info(&client->dev, "The pin %d drive mode is PIN_CONFIG_BIAS_PULL_UP\n", pin);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
// 設定下拉電阻
offs = 0x01;
dev_info(&client->dev, "The pin %d drive mode is PIN_CONFIG_BIAS_PULL_DOWN\n", pin);
break;
// ...
}
// 透過 I2C 寫入組態到 CY8C9520A
ret = i2c_smbus_write_byte_data(client, REG_DRIVE_PULLUP + offs, val);
if (ret < 0) {
dev_err(&client->dev, "can't set drive mode port %u\n", port);
goto end;
}
}
end:
mutex_unlock(&cygpio->lock);
return ret;
}
內容解密:
cygpio_pinconf_set函式的作用:該函式用於組態 CY8C9520A 的 GPIO Pin 的各種引數,如上拉/下拉電阻和驅動強度等。- 引數解析:函式中透過迴圈處理多個組態請求,每次迭代都會解析出組態引數和對應的值。
switch-case結構:根據不同的組態引數型別(如上拉/下拉電阻),決定如何設定 CY8C9520A 的暫存器。- I2C 通訊:使用
i2c_smbus_write_byte_data將組態寫入 CY8C9520A 對應的暫存器中,以完成實際的硬體組態。
GPIO 操作實作
驅動程式實作了 struct gpio_chip 結構體所需的多個回呼函式,包括 cy8c9520a_gpio_get、cy8c9520a_gpio_set 和 cy8c9520a_gpio_direction_output 等,用於支援 GPIO 的基本操作。
static int cy8c9520a_gpio_get(struct gpio_chip *chip, unsigned int gpio)
{
// ...
mutex_lock(&cygpio->lock);
ret = i2c_smbus_read_byte_data(cygpio->client, in_reg);
if (ret < 0) {
dev_err(chip->parent, "can't read input port %u\n", in_reg);
}
mutex_unlock(&cygpio->lock);
return !!(ret & BIT(cypress_get_offs(gpio, port)));
}
內容解密:
cy8c9520a_gpio_get函式的作用:讀取指定 GPIO Pin 的輸入值。- 鎖機制:使用
mutex_lock和mutex_unlock確保對 I2C 裝置的存取是執行緒安全的。 - I2C 讀取操作:透過
i2c_smbus_read_byte_data從 CY8C9520A 的輸入暫存器中讀取資料。 - 結果處理:將讀取到的值進行位元運算,以確定對應 GPIO Pin 的狀態。
此圖示
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title 此圖示
rectangle "I2C 通訊" as node1
rectangle "GPIO 操作" as node2
rectangle "Pin Control" as node3
node1 --> node2
node2 --> node3
@enduml圖示說明:
- CY8C9520A 是透過 I2C 與 Linux 核心 通訊的 GPIO 擴充套件裝置。
- Linux 核心 提供 GPIO 操作介面給 應用程式 使用。
- Linux 核心 中的 pinctrl 子系統 負責管理 Pin 的組態。
這張圖清晰地展示了 CY8C9520A 裝置與 Linux 系統之間的互動關係,以及各個元件在系統中的角色。