mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
![Linus Torvalds](/assets/img/avatar_default.png)
New drivers: - Last merge window we created a driver for the Ralink RT2880. We are now moving the Ralink SoC pin control drivers out of the MIPS architecture code and into the pin control subsystem. This concerns RT288X, MT7620, RT305X, RT3883 and MT7621. - Qualcomm SM6125 SoC pin control driver. - Qualcomm spmi-gpio support for PM7325. - Qualcomm spmi-mpp also handles PMI8994 (just a compatible string) - Mediatek MT8365 SoC pin controller. - New device HID for the AMD GPIO controller. Improvements: - Pin bias config support for a slew of Renesas pin controllers. - Incremental improvements and non-urgent bug fixes to the Renesas SoC drivers. - Implement irq_set_wake on the AMD pin controller so we can wake up from external pin events. Misc: - Devicetree bindings for the Apple M1 pin controller, we will probably see a proper driver for this soon as well. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAmDeTu0ACgkQQRCzN7AZ XXO2Yg/+LHbqYX8V+Ig1ZcY4p5bfbGyyC6QG6g3d/kzzCmsjHFgmDFQoZ+LoRx+p FRUSvmiR0VERMZCEepHsZgzns6ezzJfBt4Cu/388d4iYZppaETpQV47TzqY3eP7Q 4Shu2wIKwd7C3vNrCifub0JOYAAEsqdlHd75g0bqhal9hgH/MgYQSq9F22/TKAFl hteFwyw5L4OwKIDUpqDOIcG8thhHYWrQy77/Pp82/TVnmO9gamt863dKBjIg6iF9 c+pmIWI8K2mBhNO+epGG4VSroUudIBwKV88nwUjKSe+pu0VAU7lit/V0Uh1IhG0s FUHHGDeF62Ncn4SOYetlnSlKbQkhJaBDV2sDgQ3xzqvs1P3WEHRWqYIh1egq5iW6 /KtpSlRLQ/aO+k0iN66pErpAfsGNFAxkqlCSypyJG7ROnb2rADzZ0ftEKQb8RzZb nypPupOO5/bFfQHbQtFORDaNu9MUTR5PR04eTPMoApG0nv7zY+kcJ6iJuKE9spLb ahoxLstfQ/fKK27yms72E6PqwanuUEzcQv7gjhuHmFEjNrW1ARUqoa5hpdAzhZOX 20P8SZWkSeUZnqB26YQq+1U9p6wV0064Vp+jYY/wzQpV40dgX9oumiRkxCWCzpjt 6mw6x9txlrEEu+2WadW8yZd4ewKvWFLEGI+C/83pnI5NF1Dp0Go= =Ajcr -----END PGP SIGNATURE----- Merge tag 'pinctrl-v5.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl Pull pin control updates from Linus Walleij: "This is the bulk of pin control changes for the v5.14 kernel. Not so much going on. No core changes, just drivers. The most interesting would be that MIPS Ralink is migrating to pin control and we have some bindings but not yet code for the Apple M1 pin controller. New drivers: - Last merge window we created a driver for the Ralink RT2880. We are now moving the Ralink SoC pin control drivers out of the MIPS architecture code and into the pin control subsystem. This concerns RT288X, MT7620, RT305X, RT3883 and MT7621. - Qualcomm SM6125 SoC pin control driver. - Qualcomm spmi-gpio support for PM7325. - Qualcomm spmi-mpp also handles PMI8994 (just a compatible string) - Mediatek MT8365 SoC pin controller. - New device HID for the AMD GPIO controller. Improvements: - Pin bias config support for a slew of Renesas pin controllers. - Incremental improvements and non-urgent bug fixes to the Renesas SoC drivers. - Implement irq_set_wake on the AMD pin controller so we can wake up from external pin events. Misc: - Devicetree bindings for the Apple M1 pin controller, we will probably see a proper driver for this soon as well" * tag 'pinctrl-v5.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (54 commits) pinctrl: ralink: rt305x: add missing include pinctrl: stm32: check for IRQ MUX validity during alloc() pinctrl: zynqmp: some code cleanups drivers: qcom: pinctrl: Add pinctrl driver for sm6125 dt-bindings: pinctrl: qcom: sm6125: Document SM6125 pinctrl driver dt-bindings: pinctrl: mcp23s08: add documentation for reset-gpios pinctrl: mcp23s08: Add optional reset GPIO pinctrl: mediatek: fix mode encoding pinctrl: mcp23s08: Fix missing unlock on error in mcp23s08_irq() pinctrl: bcm: Constify static pinmux_ops pinctrl: bcm: Constify static pinctrl_ops pinctrl: ralink: move RT288X SoC pinmux config into a new 'pinctrl-rt288x.c' file pinctrl: ralink: move MT7620 SoC pinmux config into a new 'pinctrl-mt7620.c' file pinctrl: ralink: move RT305X SoC pinmux config into a new 'pinctrl-rt305x.c' file pinctrl: ralink: move RT3883 SoC pinmux config into a new 'pinctrl-rt3883.c' file pinctrl: ralink: move MT7621 SoC pinmux config into a new 'pinctrl-mt7621.c' file pinctrl: ralink: move ralink architecture pinmux header into the driver pinctrl: single: config: enable the pin's input pinctrl: mtk: Fix mt8365 Kconfig dependency pinctrl: mcp23s08: fix race condition in irq handler ...
349 lines
8.2 KiB
C
349 lines
8.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2013 John Crispin <blogic@openwrt.org>
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/io.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/of.h>
|
|
#include <linux/pinctrl/pinctrl.h>
|
|
#include <linux/pinctrl/pinconf.h>
|
|
#include <linux/pinctrl/pinconf-generic.h>
|
|
#include <linux/pinctrl/pinmux.h>
|
|
#include <linux/pinctrl/consumer.h>
|
|
#include <linux/pinctrl/machine.h>
|
|
|
|
#include <asm/mach-ralink/ralink_regs.h>
|
|
#include <asm/mach-ralink/mt7620.h>
|
|
|
|
#include "pinmux.h"
|
|
#include "../core.h"
|
|
#include "../pinctrl-utils.h"
|
|
|
|
#define SYSC_REG_GPIO_MODE 0x60
|
|
#define SYSC_REG_GPIO_MODE2 0x64
|
|
|
|
struct rt2880_priv {
|
|
struct device *dev;
|
|
|
|
struct pinctrl_pin_desc *pads;
|
|
struct pinctrl_desc *desc;
|
|
|
|
struct rt2880_pmx_func **func;
|
|
int func_count;
|
|
|
|
struct rt2880_pmx_group *groups;
|
|
const char **group_names;
|
|
int group_count;
|
|
|
|
u8 *gpio;
|
|
int max_pins;
|
|
};
|
|
|
|
static int rt2880_get_group_count(struct pinctrl_dev *pctrldev)
|
|
{
|
|
struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
|
|
|
|
return p->group_count;
|
|
}
|
|
|
|
static const char *rt2880_get_group_name(struct pinctrl_dev *pctrldev,
|
|
unsigned int group)
|
|
{
|
|
struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
|
|
|
|
return (group >= p->group_count) ? NULL : p->group_names[group];
|
|
}
|
|
|
|
static int rt2880_get_group_pins(struct pinctrl_dev *pctrldev,
|
|
unsigned int group,
|
|
const unsigned int **pins,
|
|
unsigned int *num_pins)
|
|
{
|
|
struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
|
|
|
|
if (group >= p->group_count)
|
|
return -EINVAL;
|
|
|
|
*pins = p->groups[group].func[0].pins;
|
|
*num_pins = p->groups[group].func[0].pin_count;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct pinctrl_ops rt2880_pctrl_ops = {
|
|
.get_groups_count = rt2880_get_group_count,
|
|
.get_group_name = rt2880_get_group_name,
|
|
.get_group_pins = rt2880_get_group_pins,
|
|
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
|
|
.dt_free_map = pinconf_generic_dt_free_map,
|
|
};
|
|
|
|
static int rt2880_pmx_func_count(struct pinctrl_dev *pctrldev)
|
|
{
|
|
struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
|
|
|
|
return p->func_count;
|
|
}
|
|
|
|
static const char *rt2880_pmx_func_name(struct pinctrl_dev *pctrldev,
|
|
unsigned int func)
|
|
{
|
|
struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
|
|
|
|
return p->func[func]->name;
|
|
}
|
|
|
|
static int rt2880_pmx_group_get_groups(struct pinctrl_dev *pctrldev,
|
|
unsigned int func,
|
|
const char * const **groups,
|
|
unsigned int * const num_groups)
|
|
{
|
|
struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
|
|
|
|
if (p->func[func]->group_count == 1)
|
|
*groups = &p->group_names[p->func[func]->groups[0]];
|
|
else
|
|
*groups = p->group_names;
|
|
|
|
*num_groups = p->func[func]->group_count;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rt2880_pmx_group_enable(struct pinctrl_dev *pctrldev,
|
|
unsigned int func, unsigned int group)
|
|
{
|
|
struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
|
|
u32 mode = 0;
|
|
u32 reg = SYSC_REG_GPIO_MODE;
|
|
int i;
|
|
int shift;
|
|
|
|
/* dont allow double use */
|
|
if (p->groups[group].enabled) {
|
|
dev_err(p->dev, "%s is already enabled\n",
|
|
p->groups[group].name);
|
|
return 0;
|
|
}
|
|
|
|
p->groups[group].enabled = 1;
|
|
p->func[func]->enabled = 1;
|
|
|
|
shift = p->groups[group].shift;
|
|
if (shift >= 32) {
|
|
shift -= 32;
|
|
reg = SYSC_REG_GPIO_MODE2;
|
|
}
|
|
mode = rt_sysc_r32(reg);
|
|
mode &= ~(p->groups[group].mask << shift);
|
|
|
|
/* mark the pins as gpio */
|
|
for (i = 0; i < p->groups[group].func[0].pin_count; i++)
|
|
p->gpio[p->groups[group].func[0].pins[i]] = 1;
|
|
|
|
/* function 0 is gpio and needs special handling */
|
|
if (func == 0) {
|
|
mode |= p->groups[group].gpio << shift;
|
|
} else {
|
|
for (i = 0; i < p->func[func]->pin_count; i++)
|
|
p->gpio[p->func[func]->pins[i]] = 0;
|
|
mode |= p->func[func]->value << shift;
|
|
}
|
|
rt_sysc_w32(mode, reg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rt2880_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev,
|
|
struct pinctrl_gpio_range *range,
|
|
unsigned int pin)
|
|
{
|
|
struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
|
|
|
|
if (!p->gpio[pin]) {
|
|
dev_err(p->dev, "pin %d is not set to gpio mux\n", pin);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct pinmux_ops rt2880_pmx_group_ops = {
|
|
.get_functions_count = rt2880_pmx_func_count,
|
|
.get_function_name = rt2880_pmx_func_name,
|
|
.get_function_groups = rt2880_pmx_group_get_groups,
|
|
.set_mux = rt2880_pmx_group_enable,
|
|
.gpio_request_enable = rt2880_pmx_group_gpio_request_enable,
|
|
};
|
|
|
|
static struct pinctrl_desc rt2880_pctrl_desc = {
|
|
.owner = THIS_MODULE,
|
|
.name = "rt2880-pinmux",
|
|
.pctlops = &rt2880_pctrl_ops,
|
|
.pmxops = &rt2880_pmx_group_ops,
|
|
};
|
|
|
|
static struct rt2880_pmx_func gpio_func = {
|
|
.name = "gpio",
|
|
};
|
|
|
|
static int rt2880_pinmux_index(struct rt2880_priv *p)
|
|
{
|
|
struct rt2880_pmx_group *mux = p->groups;
|
|
int i, j, c = 0;
|
|
|
|
/* count the mux functions */
|
|
while (mux->name) {
|
|
p->group_count++;
|
|
mux++;
|
|
}
|
|
|
|
/* allocate the group names array needed by the gpio function */
|
|
p->group_names = devm_kcalloc(p->dev, p->group_count,
|
|
sizeof(char *), GFP_KERNEL);
|
|
if (!p->group_names)
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < p->group_count; i++) {
|
|
p->group_names[i] = p->groups[i].name;
|
|
p->func_count += p->groups[i].func_count;
|
|
}
|
|
|
|
/* we have a dummy function[0] for gpio */
|
|
p->func_count++;
|
|
|
|
/* allocate our function and group mapping index buffers */
|
|
p->func = devm_kcalloc(p->dev, p->func_count,
|
|
sizeof(*p->func), GFP_KERNEL);
|
|
gpio_func.groups = devm_kcalloc(p->dev, p->group_count, sizeof(int),
|
|
GFP_KERNEL);
|
|
if (!p->func || !gpio_func.groups)
|
|
return -ENOMEM;
|
|
|
|
/* add a backpointer to the function so it knows its group */
|
|
gpio_func.group_count = p->group_count;
|
|
for (i = 0; i < gpio_func.group_count; i++)
|
|
gpio_func.groups[i] = i;
|
|
|
|
p->func[c] = &gpio_func;
|
|
c++;
|
|
|
|
/* add remaining functions */
|
|
for (i = 0; i < p->group_count; i++) {
|
|
for (j = 0; j < p->groups[i].func_count; j++) {
|
|
p->func[c] = &p->groups[i].func[j];
|
|
p->func[c]->groups = devm_kzalloc(p->dev, sizeof(int),
|
|
GFP_KERNEL);
|
|
if (!p->func[c]->groups)
|
|
return -ENOMEM;
|
|
p->func[c]->groups[0] = i;
|
|
p->func[c]->group_count = 1;
|
|
c++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int rt2880_pinmux_pins(struct rt2880_priv *p)
|
|
{
|
|
int i, j;
|
|
|
|
/*
|
|
* loop over the functions and initialize the pins array.
|
|
* also work out the highest pin used.
|
|
*/
|
|
for (i = 0; i < p->func_count; i++) {
|
|
int pin;
|
|
|
|
if (!p->func[i]->pin_count)
|
|
continue;
|
|
|
|
p->func[i]->pins = devm_kcalloc(p->dev,
|
|
p->func[i]->pin_count,
|
|
sizeof(int),
|
|
GFP_KERNEL);
|
|
for (j = 0; j < p->func[i]->pin_count; j++)
|
|
p->func[i]->pins[j] = p->func[i]->pin_first + j;
|
|
|
|
pin = p->func[i]->pin_first + p->func[i]->pin_count;
|
|
if (pin > p->max_pins)
|
|
p->max_pins = pin;
|
|
}
|
|
|
|
/* the buffer that tells us which pins are gpio */
|
|
p->gpio = devm_kcalloc(p->dev, p->max_pins, sizeof(u8), GFP_KERNEL);
|
|
/* the pads needed to tell pinctrl about our pins */
|
|
p->pads = devm_kcalloc(p->dev, p->max_pins,
|
|
sizeof(struct pinctrl_pin_desc), GFP_KERNEL);
|
|
if (!p->pads || !p->gpio)
|
|
return -ENOMEM;
|
|
|
|
memset(p->gpio, 1, sizeof(u8) * p->max_pins);
|
|
for (i = 0; i < p->func_count; i++) {
|
|
if (!p->func[i]->pin_count)
|
|
continue;
|
|
|
|
for (j = 0; j < p->func[i]->pin_count; j++)
|
|
p->gpio[p->func[i]->pins[j]] = 0;
|
|
}
|
|
|
|
/* pin 0 is always a gpio */
|
|
p->gpio[0] = 1;
|
|
|
|
/* set the pads */
|
|
for (i = 0; i < p->max_pins; i++) {
|
|
/* strlen("ioXY") + 1 = 5 */
|
|
char *name = devm_kzalloc(p->dev, 5, GFP_KERNEL);
|
|
|
|
if (!name)
|
|
return -ENOMEM;
|
|
snprintf(name, 5, "io%d", i);
|
|
p->pads[i].number = i;
|
|
p->pads[i].name = name;
|
|
}
|
|
p->desc->pins = p->pads;
|
|
p->desc->npins = p->max_pins;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rt2880_pinmux_init(struct platform_device *pdev,
|
|
struct rt2880_pmx_group *data)
|
|
{
|
|
struct rt2880_priv *p;
|
|
struct pinctrl_dev *dev;
|
|
int err;
|
|
|
|
if (!data)
|
|
return -ENOTSUPP;
|
|
|
|
/* setup the private data */
|
|
p = devm_kzalloc(&pdev->dev, sizeof(struct rt2880_priv), GFP_KERNEL);
|
|
if (!p)
|
|
return -ENOMEM;
|
|
|
|
p->dev = &pdev->dev;
|
|
p->desc = &rt2880_pctrl_desc;
|
|
p->groups = data;
|
|
platform_set_drvdata(pdev, p);
|
|
|
|
/* init the device */
|
|
err = rt2880_pinmux_index(p);
|
|
if (err) {
|
|
dev_err(&pdev->dev, "failed to load index\n");
|
|
return err;
|
|
}
|
|
|
|
err = rt2880_pinmux_pins(p);
|
|
if (err) {
|
|
dev_err(&pdev->dev, "failed to load pins\n");
|
|
return err;
|
|
}
|
|
dev = pinctrl_register(p->desc, &pdev->dev, p);
|
|
|
|
return PTR_ERR_OR_ZERO(dev);
|
|
}
|