Обзор
Как мы все знаем, каждая SoC имеет много контактов.Помимо контактов со специальными функциями, такими как питание, заземление и т. д., другие контакты обычно «играют несколько ролей». Например, контакт можно использовать в качестве GPIO. , также может использоваться как TX UART или MOSI SPI; более того, эти контакты часто имеют разные возможности, такие как подтягивание, понижение, различные возможности управления и т. д.
Подсистема pinctrl предназначена для выполнения вышеперечисленных функций.Pinctrl управляет всеми выводами SoC вниз и предоставляет интерфейсы для настройки всех контактов SoC вверх. Обычно при портировании системы Linux на новую SoC одной из задач является регистрация всех пинов в подсистеме pinctrl и предоставление соответствующих интерфейсов для настройки этих пинов.
Расположение подсистемы pinctrl в ядре Linux . В этой статье в основном представлены базовые настройки и использование pinctrl. Если вы хотите узнать больше о pinctrl, обратитесь к наиболее авторитетной документации ядра, в которой рассказывается о подсистеме pinctrl в ядре 5.18. Введение . Вы можете обратиться к статьям, которые я написал ранее .
эффект
Подсистема pinctrl, являющаяся важной частью встроенного Linux, обычно выполняет следующие функции:
- Перечислите и назовите все контакты SoC;
- Функция управления группой контактов; для некоторых интерфейсов, таких как spi или i2c, обычно требуется совместное использование нескольких контактов, а для одного и того же периферийного контроллера может быть несколько групп контактов. Например, комбинация контактов контроллера i2c0 может быть {21, 22} или {31, 32}. Подсистема pinctrl должна иметь возможность управлять этими группами контактов.
- Обеспечить конфигурацию мультиплексирования контактов;
- Предоставляет интерфейсы для настройки специальных возможностей выводов, таких как подтягивание, понижение, двухтактный выход, выход с открытым стоком, настройка возможностей управления нагрузкой и т. д.
Pinctrl будет управлять всеми контактами с точки зрения глобальной системы и предоставлять услуги взаимоисключающего доступа к контактам.То есть каждый контакт может использоваться только одним потребителем одновременно и может быть настроен только для одной функции.
При разработке драйверов он может быть размером с чип сетевой карты с более чем десятью линиями управляющего сигнала или всего лишь с одним светодиодом или кнопкой GPIO. Помните, что первое, что нужно сделать, это настроить функцию мультиплексирования и функцию контакты, используемые периферийными устройствами.Характеристики ввода-вывода. Например, если мы используем вывод для управления светодиодом, нам потребуется следующая конфигурация:
- Вывод мультиплексирован как GPIO.
- IO — режим вывода.
- На основе фактической аппаратной схемы определите, включены ли подтягивание и понижение напряжения, а также необходимые возможности управления.
Архитектура
Диаграмма архитектуры подсистемы pinctrl показывает, что она предоставляет два набора интерфейсов:
- Далее он обеспечивает интерфейс определения контактов и регистрации методов управления для различных аппаратных платформ.
- С другой стороны, он предоставляет интерфейсы для различных драйверов для управления выводами, такие как базовый интерфейс управления GPIO, подсистема GPIO и интерфейс взаимодействия подсистемы pinctrl.
интерфейс верхнего уровня
- Определите аппаратное обеспечение pinctrl . Фактически аппаратное обеспечение pinctrl представляет собой регистр памяти. Эти регистры могут настраивать контакты для выполнения таких задач, как мультиплексирование (мультиплексирование), настройка повышения/понижения (смещение), нагрузочная способность (грузоподъемность), возможности привода и т. д. .
- Определите все контакты , подушечки, пальцы и шарики SoC, чтобы они имели одинаковое значение, указывая на определенный вывод. Контакты, управляемые каждым аппаратным обеспечением pinctrl, принадлежат к одному и тому же пространству имен, а диапазон составляет 0 ~ maxpins. Те, которые будут пропущены, будут пропущены. штыря не существует, поэтому это пространство может быть прерывистым.
Когда каждое оборудование pinctrl инициализируется, оно регистрирует дескрипторы всех выводов, задействованных в структуре pinctrl. Вот пример SoC в корпусе PGA (Pin Grid Array).Все контакты SoC расположены следующим образом:
A B C D E F G H
8 o o o o o o o o
7 o o o o o o o o
6 o o o o o o o o
5 o o o o o o o o
4 o o o o o o o o
3 o o o o o o o o
2 o o o o o o o o
1 o o o o o o o o
Следующий код перечисляет все контакты в приведенном выше SoC. Макрос PINCTRL_PIN используется для определения номера и имени каждого контакта. Номер уникален для системы.
Примечание. Если взять приведенный выше SoC в качестве примера, порядок определения контактов здесь от 0 до 63. Этот порядок не уникален. Это зависит от нескольких аспектов: 1) расположение аппаратного регистра pingctrl; 2) простота ли он для сопоставления с номером GPIO;
#include <linux/pinctrl/pinctrl.h>
const struct pinctrl_pin_desc foo_pins[] = {
PINCTRL_PIN(0, "A8"),
PINCTRL_PIN(1, "B8"),
PINCTRL_PIN(2, "C8"),
...
PINCTRL_PIN(61, "F1"),
PINCTRL_PIN(62, "G1"),
PINCTRL_PIN(63, "H1"),
};
static struct pinctrl_desc foo_desc = {
.name = "foo",
.pins = foo_pins,
.npins = ARRAY_SIZE(foo_pins),
.owner = THIS_MODULE,
};
int __init foo_probe(void)
{
int error;
struct pinctrl_dev *pctl;
error = pinctrl_register_and_init(&foo_desc, <PARENT>,
NULL, &pctl);
if (error)
return error;
return pinctrl_enable(pctl);
}
Связь между подсистемой GPIO и подсистемой pinctrl
Подсистема GPIO управляет работой оборудования, что в конечном итоге реализуется через pinctrl. Однако обе системы имеют свои собственные пространства имен. Например, подсистема GPIO делит выводы по блокам, аналогично блоку A, блоку B и т. д., тогда как подсистема pinctrl определяется последовательно в соответствии с серийным номером выводов SoC. индексы двух системных выводов не соответствуют один к одному, что требует карты для сопоставления. Например, следующий код:
struct gpio_chip chip_a;
struct gpio_chip chip_b;
static struct pinctrl_gpio_range gpio_range_a = {
.name = "chip a",
.id = 0,
.base = 32,
.pin_base = 32,
.npins = 16,
.gc = &chip_a;
};
static struct pinctrl_gpio_range gpio_range_b = {
.name = "chip b",
.id = 0,
.base = 48,
.pin_base = 64,
.npins = 8,
.gc = &chip_b;
};
{
struct pinctrl_dev *pctl;
...
pinctrl_add_gpio_range(pctl, &gpio_range_a);
pinctrl_add_gpio_range(pctl, &gpio_range_b);
}
- чип_а и чип_b — два блока подсистемы GPIO;
- Структура pinctrl_gpio_range используется для определения отношений отображения между двумя выводами подсистемы;
- base представляет собой начальный серийный номер контакта в определенном блоке, pin_base представляет его начальный серийный номер в подсистеме pinctrl, а bpins представляет количество контактов в блоке;
Ниже приводится взаимосвязь сопоставления выводов между двумя подсистемами:
chip a:
- GPIO range : [32 .. 47]
- pin range : [32 .. 47]
chip b:
- GPIO range : [48 .. 55]
- pin range : [64 .. 71]
Обратите внимание , что в приведенном выше представлении контакты в двух подсистемах отображаются линейно. Что, если это нелинейно или случайно? Пожалуйста, посмотрите на код ниже:
static const unsigned range_pins[] = {
14, 1, 22, 17, 10, 8, 6, 2 };
static struct pinctrl_gpio_range gpio_range = {
.name = "chip",
.id = 0,
.base = 32,
.pins = &range_pins,
.npins = ARRAY_SIZE(range_pins),
.gc = &chip;
};
Обратите внимание , что для линейного сопоставления вместо pin_base используются выводы, а выводы в range_pins являются случайными.
**Вывод:** Будь то линейное или случайное сопоставление, обратите внимание, что для одного и того же вывода номер в двух системах, скорее всего, будет разным!
Когда подсистема GPIO управляет определенным контактом, она преобразует его в номер контакта в pinctrl посредством сопоставления между двумя системными контактами, тем самым управляя аппаратным обеспечением.