2013-01-19 05:30:34 +08:00
|
|
|
/*
|
|
|
|
* Allwinner A1X SoCs pinctrl driver.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Maxime Ripard
|
|
|
|
*
|
|
|
|
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
|
|
*
|
|
|
|
* This file is licensed under the terms of the GNU General Public
|
|
|
|
* License version 2. This program is licensed "as is" without any
|
|
|
|
* warranty of any kind, whether express or implied.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/io.h>
|
2013-03-22 22:20:40 +08:00
|
|
|
#include <linux/clk.h>
|
2015-12-09 05:40:43 +08:00
|
|
|
#include <linux/gpio/driver.h>
|
2013-06-08 18:05:44 +08:00
|
|
|
#include <linux/irqdomain.h>
|
2014-02-11 00:22:37 +08:00
|
|
|
#include <linux/irqchip/chained_irq.h>
|
2016-03-01 04:48:37 +08:00
|
|
|
#include <linux/export.h>
|
2013-01-19 05:30:34 +08:00
|
|
|
#include <linux/of.h>
|
2018-04-18 22:50:05 +08:00
|
|
|
#include <linux/of_clk.h>
|
2013-01-19 05:30:34 +08:00
|
|
|
#include <linux/of_address.h>
|
|
|
|
#include <linux/of_device.h>
|
2013-06-08 18:05:44 +08:00
|
|
|
#include <linux/of_irq.h>
|
2013-01-19 05:30:34 +08:00
|
|
|
#include <linux/pinctrl/consumer.h>
|
|
|
|
#include <linux/pinctrl/machine.h>
|
|
|
|
#include <linux/pinctrl/pinctrl.h>
|
|
|
|
#include <linux/pinctrl/pinconf-generic.h>
|
|
|
|
#include <linux/pinctrl/pinmux.h>
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 22:02:03 +08:00
|
|
|
#include <linux/regulator/consumer.h>
|
2013-01-19 05:30:34 +08:00
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
|
2016-10-11 23:46:00 +08:00
|
|
|
#include <dt-bindings/pinctrl/sun4i-a10.h>
|
|
|
|
|
2014-04-19 00:53:02 +08:00
|
|
|
#include "../core.h"
|
2013-01-19 05:30:34 +08:00
|
|
|
#include "pinctrl-sunxi.h"
|
2013-01-19 05:30:35 +08:00
|
|
|
|
2014-06-29 22:11:01 +08:00
|
|
|
static struct irq_chip sunxi_pinctrl_edge_irq_chip;
|
|
|
|
static struct irq_chip sunxi_pinctrl_level_irq_chip;
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
static struct sunxi_pinctrl_group *
|
|
|
|
sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pctl->ngroups; i++) {
|
|
|
|
struct sunxi_pinctrl_group *grp = pctl->groups + i;
|
|
|
|
|
|
|
|
if (!strcmp(grp->name, group))
|
|
|
|
return grp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sunxi_pinctrl_function *
|
|
|
|
sunxi_pinctrl_find_function_by_name(struct sunxi_pinctrl *pctl,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl_function *func = pctl->functions;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pctl->nfunctions; i++) {
|
|
|
|
if (!func[i].name)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!strcmp(func[i].name, name))
|
|
|
|
return func + i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sunxi_desc_function *
|
|
|
|
sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl,
|
|
|
|
const char *pin_name,
|
|
|
|
const char *func_name)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pctl->desc->npins; i++) {
|
|
|
|
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
|
|
|
|
|
|
|
|
if (!strcmp(pin->pin.name, pin_name)) {
|
|
|
|
struct sunxi_desc_function *func = pin->functions;
|
|
|
|
|
|
|
|
while (func->name) {
|
pinctrl: sunxi-pinctrl: fix pin funtion can not be match correctly.
Pin function can not be match correctly when SUNXI_PIN describe with
mutiple variant and same function.
such as:
on pinctrl-sun4i-a10.c
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION_VARIANT(0x2, "pwm", /* PWM0 */
PINCTRL_SUN4I_A10 |
PINCTRL_SUN7I_A20),
SUNXI_FUNCTION_VARIANT(0x3, "pwm", /* PWM0 */
PINCTRL_SUN8I_R40)),
it would always match to the first variant function
(PINCTRL_SUN4I_A10, PINCTRL_SUN7I_A20)
so we should add variant compare on it.
Signed-off-by: hao_zhang <hao5781286@gmail.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-01-09 13:59:02 +08:00
|
|
|
if (!strcmp(func->name, func_name) &&
|
|
|
|
(!func->variant ||
|
|
|
|
func->variant & pctl->variant))
|
2013-01-19 05:30:34 +08:00
|
|
|
return func;
|
|
|
|
|
|
|
|
func++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-06-08 18:05:43 +08:00
|
|
|
static struct sunxi_desc_function *
|
|
|
|
sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl,
|
|
|
|
const u16 pin_num,
|
|
|
|
const char *func_name)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pctl->desc->npins; i++) {
|
|
|
|
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
|
|
|
|
|
|
|
|
if (pin->pin.number == pin_num) {
|
|
|
|
struct sunxi_desc_function *func = pin->functions;
|
|
|
|
|
|
|
|
while (func->name) {
|
|
|
|
if (!strcmp(func->name, func_name))
|
|
|
|
return func;
|
|
|
|
|
|
|
|
func++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
return pctl->ngroups;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *sunxi_pctrl_get_group_name(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned group)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
return pctl->groups[group].name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sunxi_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned group,
|
|
|
|
const unsigned **pins,
|
|
|
|
unsigned *num_pins)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
*pins = (unsigned *)&pctl->groups[group].pin;
|
|
|
|
*num_pins = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-11 23:45:59 +08:00
|
|
|
static bool sunxi_pctrl_has_bias_prop(struct device_node *node)
|
|
|
|
{
|
2016-10-20 21:49:03 +08:00
|
|
|
return of_find_property(node, "bias-pull-up", NULL) ||
|
|
|
|
of_find_property(node, "bias-pull-down", NULL) ||
|
|
|
|
of_find_property(node, "bias-disable", NULL) ||
|
|
|
|
of_find_property(node, "allwinner,pull", NULL);
|
2016-10-11 23:45:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool sunxi_pctrl_has_drive_prop(struct device_node *node)
|
|
|
|
{
|
2016-10-20 21:49:03 +08:00
|
|
|
return of_find_property(node, "drive-strength", NULL) ||
|
|
|
|
of_find_property(node, "allwinner,drive", NULL);
|
2016-10-11 23:45:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int sunxi_pctrl_parse_bias_prop(struct device_node *node)
|
|
|
|
{
|
|
|
|
u32 val;
|
|
|
|
|
2016-10-20 21:49:03 +08:00
|
|
|
/* Try the new style binding */
|
|
|
|
if (of_find_property(node, "bias-pull-up", NULL))
|
|
|
|
return PIN_CONFIG_BIAS_PULL_UP;
|
|
|
|
|
|
|
|
if (of_find_property(node, "bias-pull-down", NULL))
|
|
|
|
return PIN_CONFIG_BIAS_PULL_DOWN;
|
|
|
|
|
|
|
|
if (of_find_property(node, "bias-disable", NULL))
|
|
|
|
return PIN_CONFIG_BIAS_DISABLE;
|
|
|
|
|
|
|
|
/* And fall back to the old binding */
|
2016-10-11 23:45:59 +08:00
|
|
|
if (of_property_read_u32(node, "allwinner,pull", &val))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
switch (val) {
|
2016-10-11 23:46:01 +08:00
|
|
|
case SUN4I_PINCTRL_NO_PULL:
|
|
|
|
return PIN_CONFIG_BIAS_DISABLE;
|
2016-10-11 23:46:00 +08:00
|
|
|
case SUN4I_PINCTRL_PULL_UP:
|
2016-10-11 23:45:59 +08:00
|
|
|
return PIN_CONFIG_BIAS_PULL_UP;
|
2016-10-11 23:46:00 +08:00
|
|
|
case SUN4I_PINCTRL_PULL_DOWN:
|
2016-10-11 23:45:59 +08:00
|
|
|
return PIN_CONFIG_BIAS_PULL_DOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sunxi_pctrl_parse_drive_prop(struct device_node *node)
|
|
|
|
{
|
|
|
|
u32 val;
|
|
|
|
|
2016-10-20 21:49:03 +08:00
|
|
|
/* Try the new style binding */
|
|
|
|
if (!of_property_read_u32(node, "drive-strength", &val)) {
|
|
|
|
/* We can't go below 10mA ... */
|
|
|
|
if (val < 10)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* ... and only up to 40 mA ... */
|
|
|
|
if (val > 40)
|
|
|
|
val = 40;
|
|
|
|
|
|
|
|
/* by steps of 10 mA */
|
|
|
|
return rounddown(val, 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* And then fall back to the old binding */
|
2016-10-11 23:45:59 +08:00
|
|
|
if (of_property_read_u32(node, "allwinner,drive", &val))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return (val + 1) * 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *sunxi_pctrl_parse_function_prop(struct device_node *node)
|
|
|
|
{
|
|
|
|
const char *function;
|
|
|
|
int ret;
|
|
|
|
|
2016-10-20 21:49:03 +08:00
|
|
|
/* Try the generic binding */
|
|
|
|
ret = of_property_read_string(node, "function", &function);
|
|
|
|
if (!ret)
|
|
|
|
return function;
|
|
|
|
|
|
|
|
/* And fall back to our legacy one */
|
2016-10-11 23:45:59 +08:00
|
|
|
ret = of_property_read_string(node, "allwinner,function", &function);
|
|
|
|
if (!ret)
|
|
|
|
return function;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *sunxi_pctrl_find_pins_prop(struct device_node *node,
|
|
|
|
int *npins)
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
|
2016-10-20 21:49:03 +08:00
|
|
|
/* Try the generic binding */
|
|
|
|
count = of_property_count_strings(node, "pins");
|
|
|
|
if (count > 0) {
|
|
|
|
*npins = count;
|
|
|
|
return "pins";
|
|
|
|
}
|
|
|
|
|
|
|
|
/* And fall back to our legacy one */
|
2016-10-11 23:45:59 +08:00
|
|
|
count = of_property_count_strings(node, "allwinner,pins");
|
|
|
|
if (count > 0) {
|
|
|
|
*npins = count;
|
|
|
|
return "allwinner,pins";
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long *sunxi_pctrl_build_pin_config(struct device_node *node,
|
|
|
|
unsigned int *len)
|
|
|
|
{
|
|
|
|
unsigned long *pinconfig;
|
|
|
|
unsigned int configlen = 0, idx = 0;
|
2016-10-20 21:49:02 +08:00
|
|
|
int ret;
|
2016-10-11 23:45:59 +08:00
|
|
|
|
|
|
|
if (sunxi_pctrl_has_drive_prop(node))
|
|
|
|
configlen++;
|
|
|
|
if (sunxi_pctrl_has_bias_prop(node))
|
|
|
|
configlen++;
|
|
|
|
|
2016-10-20 21:49:02 +08:00
|
|
|
/*
|
|
|
|
* If we don't have any configuration, bail out
|
|
|
|
*/
|
|
|
|
if (!configlen)
|
|
|
|
return NULL;
|
|
|
|
|
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 05:03:40 +08:00
|
|
|
pinconfig = kcalloc(configlen, sizeof(*pinconfig), GFP_KERNEL);
|
2016-10-11 23:45:59 +08:00
|
|
|
if (!pinconfig)
|
2016-10-20 21:49:02 +08:00
|
|
|
return ERR_PTR(-ENOMEM);
|
2016-10-11 23:45:59 +08:00
|
|
|
|
|
|
|
if (sunxi_pctrl_has_drive_prop(node)) {
|
|
|
|
int drive = sunxi_pctrl_parse_drive_prop(node);
|
2016-10-20 21:49:02 +08:00
|
|
|
if (drive < 0) {
|
|
|
|
ret = drive;
|
2016-10-11 23:45:59 +08:00
|
|
|
goto err_free;
|
2016-10-20 21:49:02 +08:00
|
|
|
}
|
2016-10-11 23:45:59 +08:00
|
|
|
|
|
|
|
pinconfig[idx++] = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
|
|
|
|
drive);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sunxi_pctrl_has_bias_prop(node)) {
|
|
|
|
int pull = sunxi_pctrl_parse_bias_prop(node);
|
2016-11-11 17:50:34 +08:00
|
|
|
int arg = 0;
|
2016-10-20 21:49:02 +08:00
|
|
|
if (pull < 0) {
|
|
|
|
ret = pull;
|
2016-10-11 23:45:59 +08:00
|
|
|
goto err_free;
|
2016-10-20 21:49:02 +08:00
|
|
|
}
|
2016-10-11 23:45:59 +08:00
|
|
|
|
2016-11-11 17:50:34 +08:00
|
|
|
if (pull != PIN_CONFIG_BIAS_DISABLE)
|
|
|
|
arg = 1; /* hardware uses weak pull resistors */
|
|
|
|
|
|
|
|
pinconfig[idx++] = pinconf_to_config_packed(pull, arg);
|
2016-10-11 23:45:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
*len = configlen;
|
|
|
|
return pinconfig;
|
|
|
|
|
|
|
|
err_free:
|
|
|
|
kfree(pinconfig);
|
2016-10-20 21:49:02 +08:00
|
|
|
return ERR_PTR(ret);
|
2016-10-11 23:45:59 +08:00
|
|
|
}
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
|
|
|
|
struct device_node *node,
|
|
|
|
struct pinctrl_map **map,
|
|
|
|
unsigned *num_maps)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
unsigned long *pinconfig;
|
|
|
|
struct property *prop;
|
2016-10-11 23:45:59 +08:00
|
|
|
const char *function, *pin_prop;
|
2013-01-19 05:30:34 +08:00
|
|
|
const char *group;
|
2016-10-11 23:45:59 +08:00
|
|
|
int ret, npins, nmaps, configlen = 0, i = 0;
|
2013-01-19 05:30:34 +08:00
|
|
|
|
|
|
|
*map = NULL;
|
|
|
|
*num_maps = 0;
|
|
|
|
|
2016-10-11 23:45:59 +08:00
|
|
|
function = sunxi_pctrl_parse_function_prop(node);
|
|
|
|
if (!function) {
|
2018-08-28 09:52:41 +08:00
|
|
|
dev_err(pctl->dev, "missing function property in node %pOFn\n",
|
|
|
|
node);
|
2013-01-19 05:30:34 +08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-10-11 23:45:59 +08:00
|
|
|
pin_prop = sunxi_pctrl_find_pins_prop(node, &npins);
|
|
|
|
if (!pin_prop) {
|
2018-08-28 09:52:41 +08:00
|
|
|
dev_err(pctl->dev, "missing pins property in node %pOFn\n",
|
|
|
|
node);
|
2013-01-19 05:30:34 +08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-10-11 23:45:59 +08:00
|
|
|
/*
|
|
|
|
* We have two maps for each pin: one for the function, one
|
2016-10-20 21:49:02 +08:00
|
|
|
* for the configuration (bias, strength, etc).
|
|
|
|
*
|
|
|
|
* We might be slightly overshooting, since we might not have
|
|
|
|
* any configuration.
|
2016-10-11 23:45:59 +08:00
|
|
|
*/
|
|
|
|
nmaps = npins * 2;
|
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 04:55:00 +08:00
|
|
|
*map = kmalloc_array(nmaps, sizeof(struct pinctrl_map), GFP_KERNEL);
|
2013-07-29 16:19:32 +08:00
|
|
|
if (!*map)
|
2013-01-19 05:30:34 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-10-11 23:45:59 +08:00
|
|
|
pinconfig = sunxi_pctrl_build_pin_config(node, &configlen);
|
2016-10-20 21:49:02 +08:00
|
|
|
if (IS_ERR(pinconfig)) {
|
|
|
|
ret = PTR_ERR(pinconfig);
|
2016-10-11 23:45:59 +08:00
|
|
|
goto err_free_map;
|
|
|
|
}
|
|
|
|
|
|
|
|
of_property_for_each_string(node, pin_prop, prop, group) {
|
2013-01-19 05:30:34 +08:00
|
|
|
struct sunxi_pinctrl_group *grp =
|
|
|
|
sunxi_pinctrl_find_group_by_name(pctl, group);
|
|
|
|
|
|
|
|
if (!grp) {
|
|
|
|
dev_err(pctl->dev, "unknown pin %s", group);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sunxi_pinctrl_desc_find_function_by_name(pctl,
|
|
|
|
grp->name,
|
|
|
|
function)) {
|
|
|
|
dev_err(pctl->dev, "unsupported function %s on pin %s",
|
|
|
|
function, group);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*map)[i].type = PIN_MAP_TYPE_MUX_GROUP;
|
|
|
|
(*map)[i].data.mux.group = group;
|
|
|
|
(*map)[i].data.mux.function = function;
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
2016-10-20 21:49:02 +08:00
|
|
|
if (pinconfig) {
|
|
|
|
(*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
|
|
|
|
(*map)[i].data.configs.group_or_pin = group;
|
|
|
|
(*map)[i].data.configs.configs = pinconfig;
|
|
|
|
(*map)[i].data.configs.num_configs = configlen;
|
|
|
|
i++;
|
|
|
|
}
|
2013-01-19 05:30:34 +08:00
|
|
|
}
|
|
|
|
|
2016-10-20 21:49:02 +08:00
|
|
|
*num_maps = i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We know have the number of maps we need, we can resize our
|
|
|
|
* map array
|
|
|
|
*/
|
|
|
|
*map = krealloc(*map, i * sizeof(struct pinctrl_map), GFP_KERNEL);
|
2016-11-18 19:35:57 +08:00
|
|
|
if (!*map)
|
2016-10-20 21:49:02 +08:00
|
|
|
return -ENOMEM;
|
2013-01-19 05:30:34 +08:00
|
|
|
|
|
|
|
return 0;
|
2016-10-11 23:45:59 +08:00
|
|
|
|
|
|
|
err_free_map:
|
2016-11-18 19:35:57 +08:00
|
|
|
kfree(*map);
|
|
|
|
*map = NULL;
|
2016-10-11 23:45:59 +08:00
|
|
|
return ret;
|
2013-01-19 05:30:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
|
|
|
|
struct pinctrl_map *map,
|
|
|
|
unsigned num_maps)
|
|
|
|
{
|
2016-11-11 10:35:10 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
/* pin config is never in the first map */
|
|
|
|
for (i = 1; i < num_maps; i++) {
|
|
|
|
if (map[i].type != PIN_MAP_TYPE_CONFIGS_GROUP)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All the maps share the same pin config,
|
|
|
|
* free only the first one we find.
|
|
|
|
*/
|
|
|
|
kfree(map[i].data.configs.configs);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
kfree(map);
|
|
|
|
}
|
|
|
|
|
2013-02-16 17:25:07 +08:00
|
|
|
static const struct pinctrl_ops sunxi_pctrl_ops = {
|
2013-01-19 05:30:34 +08:00
|
|
|
.dt_node_to_map = sunxi_pctrl_dt_node_to_map,
|
|
|
|
.dt_free_map = sunxi_pctrl_dt_free_map,
|
|
|
|
.get_groups_count = sunxi_pctrl_get_groups_count,
|
|
|
|
.get_group_name = sunxi_pctrl_get_group_name,
|
|
|
|
.get_group_pins = sunxi_pctrl_get_group_pins,
|
|
|
|
};
|
|
|
|
|
2016-11-11 17:50:35 +08:00
|
|
|
static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param,
|
|
|
|
u32 *offset, u32 *shift, u32 *mask)
|
|
|
|
{
|
|
|
|
switch (param) {
|
|
|
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
|
|
|
*offset = sunxi_dlevel_reg(pin);
|
|
|
|
*shift = sunxi_dlevel_offset(pin);
|
|
|
|
*mask = DLEVEL_PINS_MASK;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PIN_CONFIG_BIAS_PULL_UP:
|
|
|
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
|
|
|
*offset = sunxi_pull_reg(pin);
|
|
|
|
*shift = sunxi_pull_offset(pin);
|
|
|
|
*mask = PULL_PINS_MASK;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -ENOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
|
|
|
|
unsigned long *config)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
enum pin_config_param param = pinconf_to_config_param(*config);
|
|
|
|
u32 offset, shift, mask, val;
|
|
|
|
u16 arg;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
pin -= pctl->desc->pin_base;
|
|
|
|
|
|
|
|
ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
val = (readl(pctl->membase + offset) >> shift) & mask;
|
|
|
|
|
|
|
|
switch (pinconf_to_config_param(*config)) {
|
|
|
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
|
|
|
arg = (val + 1) * 10;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PIN_CONFIG_BIAS_PULL_UP:
|
|
|
|
if (val != SUN4I_PINCTRL_PULL_UP)
|
|
|
|
return -EINVAL;
|
|
|
|
arg = 1; /* hardware is weak pull-up */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
|
|
if (val != SUN4I_PINCTRL_PULL_DOWN)
|
|
|
|
return -EINVAL;
|
|
|
|
arg = 1; /* hardware is weak pull-down */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
|
|
|
if (val != SUN4I_PINCTRL_NO_PULL)
|
|
|
|
return -EINVAL;
|
|
|
|
arg = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* sunxi_pconf_reg should catch anything unsupported */
|
|
|
|
WARN_ON(1);
|
|
|
|
return -ENOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
*config = pinconf_to_config_packed(param, arg);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned group,
|
|
|
|
unsigned long *config)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
2016-11-11 17:50:35 +08:00
|
|
|
struct sunxi_pinctrl_group *g = &pctl->groups[group];
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2016-11-11 17:50:35 +08:00
|
|
|
/* We only support 1 pin per group. Chain it to the pin callback */
|
|
|
|
return sunxi_pconf_get(pctldev, g->pin, config);
|
2013-01-19 05:30:34 +08:00
|
|
|
}
|
|
|
|
|
2019-03-15 03:32:51 +08:00
|
|
|
static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
|
|
|
|
unsigned long *configs, unsigned num_configs)
|
2013-01-19 05:30:34 +08:00
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
2013-08-28 02:32:12 +08:00
|
|
|
int i;
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2013-08-28 02:32:12 +08:00
|
|
|
for (i = 0; i < num_configs; i++) {
|
2016-11-11 17:50:36 +08:00
|
|
|
enum pin_config_param param;
|
|
|
|
unsigned long flags;
|
|
|
|
u32 offset, shift, mask, reg;
|
2017-01-23 20:34:32 +08:00
|
|
|
u32 arg, val;
|
2016-11-11 17:50:36 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
param = pinconf_to_config_param(configs[i]);
|
|
|
|
arg = pinconf_to_config_argument(configs[i]);
|
|
|
|
|
|
|
|
ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
switch (param) {
|
2013-08-28 02:32:12 +08:00
|
|
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
2016-11-11 17:50:36 +08:00
|
|
|
if (arg < 10 || arg > 40)
|
2013-08-28 02:32:12 +08:00
|
|
|
return -EINVAL;
|
|
|
|
/*
|
|
|
|
* We convert from mA to what the register expects:
|
|
|
|
* 0: 10mA
|
|
|
|
* 1: 20mA
|
|
|
|
* 2: 30mA
|
|
|
|
* 3: 40mA
|
|
|
|
*/
|
2016-11-11 17:50:36 +08:00
|
|
|
val = arg / 10 - 1;
|
2013-08-28 02:32:12 +08:00
|
|
|
break;
|
2016-10-11 23:46:01 +08:00
|
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
2017-08-27 20:55:23 +08:00
|
|
|
val = 0;
|
|
|
|
break;
|
2013-08-28 02:32:12 +08:00
|
|
|
case PIN_CONFIG_BIAS_PULL_UP:
|
2016-11-11 17:50:36 +08:00
|
|
|
if (arg == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
val = 1;
|
2013-08-28 02:32:12 +08:00
|
|
|
break;
|
|
|
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
2016-11-11 17:50:36 +08:00
|
|
|
if (arg == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
val = 2;
|
2013-08-28 02:32:12 +08:00
|
|
|
break;
|
|
|
|
default:
|
2016-11-11 17:50:36 +08:00
|
|
|
/* sunxi_pconf_reg should catch anything unsupported */
|
|
|
|
WARN_ON(1);
|
|
|
|
return -ENOTSUPP;
|
2013-08-28 02:32:12 +08:00
|
|
|
}
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_lock_irqsave(&pctl->lock, flags);
|
2016-11-11 17:50:36 +08:00
|
|
|
reg = readl(pctl->membase + offset);
|
|
|
|
reg &= ~(mask << shift);
|
|
|
|
writel(reg | val << shift, pctl->membase + offset);
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_unlock_irqrestore(&pctl->lock, flags);
|
2016-11-11 17:50:36 +08:00
|
|
|
} /* for each config */
|
2013-01-19 05:30:34 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-15 03:32:51 +08:00
|
|
|
static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
|
|
|
|
unsigned long *configs, unsigned num_configs)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
struct sunxi_pinctrl_group *g = &pctl->groups[group];
|
|
|
|
|
|
|
|
/* We only support 1 pin per group. Chain it to the pin callback */
|
|
|
|
return sunxi_pconf_set(pctldev, g->pin, configs, num_configs);
|
|
|
|
}
|
|
|
|
|
2013-02-16 17:25:07 +08:00
|
|
|
static const struct pinconf_ops sunxi_pconf_ops = {
|
2016-11-11 17:50:35 +08:00
|
|
|
.is_generic = true,
|
|
|
|
.pin_config_get = sunxi_pconf_get,
|
2019-03-15 03:32:51 +08:00
|
|
|
.pin_config_set = sunxi_pconf_set,
|
2013-01-19 05:30:34 +08:00
|
|
|
.pin_config_group_get = sunxi_pconf_group_get,
|
|
|
|
.pin_config_group_set = sunxi_pconf_group_set,
|
|
|
|
};
|
|
|
|
|
2019-02-06 11:32:31 +08:00
|
|
|
static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
|
|
|
|
unsigned pin,
|
|
|
|
struct regulator *supply)
|
|
|
|
{
|
2019-04-14 00:54:13 +08:00
|
|
|
unsigned short bank = pin / PINS_PER_BANK;
|
|
|
|
unsigned long flags;
|
2019-02-06 11:32:31 +08:00
|
|
|
u32 val, reg;
|
|
|
|
int uV;
|
|
|
|
|
2019-04-14 00:54:12 +08:00
|
|
|
if (!pctl->desc->io_bias_cfg_variant)
|
2019-02-06 11:32:31 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
uV = regulator_get_voltage(supply);
|
|
|
|
if (uV < 0)
|
|
|
|
return uV;
|
|
|
|
|
|
|
|
/* Might be dummy regulator with no voltage set */
|
|
|
|
if (uV == 0)
|
|
|
|
return 0;
|
|
|
|
|
2019-04-14 00:54:12 +08:00
|
|
|
switch (pctl->desc->io_bias_cfg_variant) {
|
|
|
|
case BIAS_VOLTAGE_GRP_CONFIG:
|
|
|
|
/*
|
|
|
|
* Configured value must be equal or greater to actual
|
|
|
|
* voltage.
|
|
|
|
*/
|
|
|
|
if (uV <= 1800000)
|
|
|
|
val = 0x0; /* 1.8V */
|
|
|
|
else if (uV <= 2500000)
|
|
|
|
val = 0x6; /* 2.5V */
|
|
|
|
else if (uV <= 2800000)
|
|
|
|
val = 0x9; /* 2.8V */
|
|
|
|
else if (uV <= 3000000)
|
|
|
|
val = 0xA; /* 3.0V */
|
|
|
|
else
|
|
|
|
val = 0xD; /* 3.3V */
|
|
|
|
|
|
|
|
pin -= pctl->desc->pin_base;
|
|
|
|
|
|
|
|
reg = readl(pctl->membase + sunxi_grp_config_reg(pin));
|
|
|
|
reg &= ~IO_BIAS_MASK;
|
|
|
|
writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin));
|
|
|
|
return 0;
|
2019-04-14 00:54:13 +08:00
|
|
|
case BIAS_VOLTAGE_PIO_POW_MODE_SEL:
|
|
|
|
val = uV <= 1800000 ? 1 : 0;
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&pctl->lock, flags);
|
|
|
|
reg = readl(pctl->membase + PIO_POW_MOD_SEL_REG);
|
|
|
|
reg &= ~(1 << bank);
|
|
|
|
writel(reg | val << bank, pctl->membase + PIO_POW_MOD_SEL_REG);
|
|
|
|
raw_spin_unlock_irqrestore(&pctl->lock, flags);
|
|
|
|
return 0;
|
2019-04-14 00:54:12 +08:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2019-02-06 11:32:31 +08:00
|
|
|
}
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
static int sunxi_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
return pctl->nfunctions;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *sunxi_pmx_get_func_name(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned function)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
return pctl->functions[function].name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sunxi_pmx_get_func_groups(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned function,
|
|
|
|
const char * const **groups,
|
|
|
|
unsigned * const num_groups)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
*groups = pctl->functions[function].groups;
|
|
|
|
*num_groups = pctl->functions[function].ngroups;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned pin,
|
|
|
|
u8 config)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
2013-08-04 18:38:48 +08:00
|
|
|
unsigned long flags;
|
|
|
|
u32 val, mask;
|
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_lock_irqsave(&pctl->lock, flags);
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2014-05-22 23:20:55 +08:00
|
|
|
pin -= pctl->desc->pin_base;
|
2013-08-04 18:38:48 +08:00
|
|
|
val = readl(pctl->membase + sunxi_mux_reg(pin));
|
|
|
|
mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
|
2013-01-19 05:30:34 +08:00
|
|
|
writel((val & ~mask) | config << sunxi_mux_offset(pin),
|
|
|
|
pctl->membase + sunxi_mux_reg(pin));
|
2013-08-04 18:38:48 +08:00
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_unlock_irqrestore(&pctl->lock, flags);
|
2013-01-19 05:30:34 +08:00
|
|
|
}
|
|
|
|
|
2014-09-03 19:02:56 +08:00
|
|
|
static int sunxi_pmx_set_mux(struct pinctrl_dev *pctldev,
|
|
|
|
unsigned function,
|
|
|
|
unsigned group)
|
2013-01-19 05:30:34 +08:00
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
struct sunxi_pinctrl_group *g = pctl->groups + group;
|
|
|
|
struct sunxi_pinctrl_function *func = pctl->functions + function;
|
|
|
|
struct sunxi_desc_function *desc =
|
|
|
|
sunxi_pinctrl_desc_find_function_by_name(pctl,
|
|
|
|
g->name,
|
|
|
|
func->name);
|
|
|
|
|
|
|
|
if (!desc)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
sunxi_pmx_set(pctldev, g->pin, desc->muxval);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-29 04:33:12 +08:00
|
|
|
static int
|
|
|
|
sunxi_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|
|
|
struct pinctrl_gpio_range *range,
|
|
|
|
unsigned offset,
|
|
|
|
bool input)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
struct sunxi_desc_function *desc;
|
|
|
|
const char *func;
|
|
|
|
|
|
|
|
if (input)
|
|
|
|
func = "gpio_in";
|
|
|
|
else
|
|
|
|
func = "gpio_out";
|
|
|
|
|
2013-06-08 18:05:43 +08:00
|
|
|
desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, func);
|
|
|
|
if (!desc)
|
|
|
|
return -EINVAL;
|
2013-01-29 04:33:12 +08:00
|
|
|
|
|
|
|
sunxi_pmx_set(pctldev, offset, desc->muxval);
|
|
|
|
|
2013-06-08 18:05:43 +08:00
|
|
|
return 0;
|
2013-01-29 04:33:12 +08:00
|
|
|
}
|
|
|
|
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 22:02:03 +08:00
|
|
|
static int sunxi_pmx_request(struct pinctrl_dev *pctldev, unsigned offset)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
unsigned short bank = offset / PINS_PER_BANK;
|
pinctrl: sunxi: Consider pin_base when calculating regulator array index
On most newer Allwinner SoCs, there are two pinctrl devices, the PIO and
R_PIO. PIO covers pin-banks PA to PI (PJ and PK have not been seen),
while R_PIO covers PL to PN. The regulator array only has space for 12
entries, which was designed to cover PA to PL. On the A80, the pin banks
go up to PN, which would be the 14th entry in the regulator array.
However since the driver only needs to track regulators for its own pin
banks, the array only needs to have 9 entries, and also take in to
account the value of pin_base, such that the regulator for the first
pin-bank of the pinctrl device, be it "PA" or "PL" uses the first entry
of the array.
Base the regulator array index on pin_base, such that "PA" for PIO and
"PL" for R_PIO both take the first element within their respective
device's regulator array.
Also decrease the size of the regulator array to 9, just enough to cover
"PA" to "PI".
Fixes: 9a2a566adb00 ("pinctrl: sunxi: Deal with per-bank regulators")
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2019-01-13 17:57:23 +08:00
|
|
|
unsigned short bank_offset = bank - pctl->desc->pin_base /
|
|
|
|
PINS_PER_BANK;
|
|
|
|
struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset];
|
2019-01-13 17:57:22 +08:00
|
|
|
struct regulator *reg = s_reg->regulator;
|
|
|
|
char supply[16];
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 22:02:03 +08:00
|
|
|
int ret;
|
|
|
|
|
2019-01-13 17:57:22 +08:00
|
|
|
if (reg) {
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 22:02:03 +08:00
|
|
|
refcount_inc(&s_reg->refcount);
|
2019-01-13 17:57:22 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(supply, sizeof(supply), "vcc-p%c", 'a' + bank);
|
|
|
|
reg = regulator_get(pctl->dev, supply);
|
|
|
|
if (IS_ERR(reg)) {
|
|
|
|
dev_err(pctl->dev, "Couldn't get bank P%c regulator\n",
|
|
|
|
'A' + bank);
|
|
|
|
return PTR_ERR(reg);
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 22:02:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = regulator_enable(reg);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(pctl->dev,
|
|
|
|
"Couldn't enable bank P%c regulator\n", 'A' + bank);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2019-02-06 11:32:31 +08:00
|
|
|
sunxi_pinctrl_set_io_bias_cfg(pctl, offset, reg);
|
|
|
|
|
2019-01-13 17:57:22 +08:00
|
|
|
s_reg->regulator = reg;
|
|
|
|
refcount_set(&s_reg->refcount, 1);
|
|
|
|
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 22:02:03 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
out:
|
2019-01-13 17:57:22 +08:00
|
|
|
regulator_put(s_reg->regulator);
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 22:02:03 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sunxi_pmx_free(struct pinctrl_dev *pctldev, unsigned offset)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
unsigned short bank = offset / PINS_PER_BANK;
|
pinctrl: sunxi: Consider pin_base when calculating regulator array index
On most newer Allwinner SoCs, there are two pinctrl devices, the PIO and
R_PIO. PIO covers pin-banks PA to PI (PJ and PK have not been seen),
while R_PIO covers PL to PN. The regulator array only has space for 12
entries, which was designed to cover PA to PL. On the A80, the pin banks
go up to PN, which would be the 14th entry in the regulator array.
However since the driver only needs to track regulators for its own pin
banks, the array only needs to have 9 entries, and also take in to
account the value of pin_base, such that the regulator for the first
pin-bank of the pinctrl device, be it "PA" or "PL" uses the first entry
of the array.
Base the regulator array index on pin_base, such that "PA" for PIO and
"PL" for R_PIO both take the first element within their respective
device's regulator array.
Also decrease the size of the regulator array to 9, just enough to cover
"PA" to "PI".
Fixes: 9a2a566adb00 ("pinctrl: sunxi: Deal with per-bank regulators")
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2019-01-13 17:57:23 +08:00
|
|
|
unsigned short bank_offset = bank - pctl->desc->pin_base /
|
|
|
|
PINS_PER_BANK;
|
|
|
|
struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset];
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 22:02:03 +08:00
|
|
|
|
|
|
|
if (!refcount_dec_and_test(&s_reg->refcount))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
regulator_disable(s_reg->regulator);
|
|
|
|
regulator_put(s_reg->regulator);
|
|
|
|
s_reg->regulator = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-16 17:25:07 +08:00
|
|
|
static const struct pinmux_ops sunxi_pmx_ops = {
|
2013-01-19 05:30:34 +08:00
|
|
|
.get_functions_count = sunxi_pmx_get_funcs_cnt,
|
|
|
|
.get_function_name = sunxi_pmx_get_func_name,
|
|
|
|
.get_function_groups = sunxi_pmx_get_func_groups,
|
2014-09-03 19:02:56 +08:00
|
|
|
.set_mux = sunxi_pmx_set_mux,
|
2013-01-29 04:33:12 +08:00
|
|
|
.gpio_set_direction = sunxi_pmx_gpio_set_direction,
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 22:02:03 +08:00
|
|
|
.request = sunxi_pmx_request,
|
|
|
|
.free = sunxi_pmx_free,
|
2017-10-10 04:53:39 +08:00
|
|
|
.strict = true,
|
2013-01-19 05:30:34 +08:00
|
|
|
};
|
|
|
|
|
2013-01-29 04:33:12 +08:00
|
|
|
static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
|
|
|
|
unsigned offset)
|
|
|
|
{
|
|
|
|
return pinctrl_gpio_direction_input(chip->base + offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
|
|
{
|
2015-12-09 05:40:43 +08:00
|
|
|
struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
|
2013-01-29 04:33:12 +08:00
|
|
|
u32 reg = sunxi_data_reg(offset);
|
|
|
|
u8 index = sunxi_data_offset(offset);
|
2016-02-12 03:16:45 +08:00
|
|
|
bool set_mux = pctl->desc->irq_read_needs_mux &&
|
|
|
|
gpiochip_line_is_irq(chip, offset);
|
2016-02-09 22:58:49 +08:00
|
|
|
u32 pin = offset + chip->base;
|
2015-03-09 05:13:57 +08:00
|
|
|
u32 val;
|
|
|
|
|
|
|
|
if (set_mux)
|
2016-02-09 22:58:49 +08:00
|
|
|
sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT);
|
2015-03-09 05:13:57 +08:00
|
|
|
|
|
|
|
val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
|
|
|
|
|
|
|
|
if (set_mux)
|
2016-02-09 22:58:49 +08:00
|
|
|
sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ);
|
2013-01-29 04:33:12 +08:00
|
|
|
|
2015-12-21 23:40:27 +08:00
|
|
|
return !!val;
|
2013-01-29 04:33:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
|
|
|
|
unsigned offset, int value)
|
|
|
|
{
|
2015-12-09 05:40:43 +08:00
|
|
|
struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
|
2013-01-29 04:33:12 +08:00
|
|
|
u32 reg = sunxi_data_reg(offset);
|
|
|
|
u8 index = sunxi_data_offset(offset);
|
2013-08-04 18:38:48 +08:00
|
|
|
unsigned long flags;
|
|
|
|
u32 regval;
|
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_lock_irqsave(&pctl->lock, flags);
|
2013-08-04 18:38:48 +08:00
|
|
|
|
|
|
|
regval = readl(pctl->membase + reg);
|
2013-01-29 04:33:12 +08:00
|
|
|
|
2013-07-25 18:41:16 +08:00
|
|
|
if (value)
|
|
|
|
regval |= BIT(index);
|
|
|
|
else
|
|
|
|
regval &= ~(BIT(index));
|
2013-01-29 04:33:12 +08:00
|
|
|
|
2013-07-25 18:41:16 +08:00
|
|
|
writel(regval, pctl->membase + reg);
|
2013-08-04 18:38:48 +08:00
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_unlock_irqrestore(&pctl->lock, flags);
|
2013-01-29 04:33:12 +08:00
|
|
|
}
|
|
|
|
|
2014-01-16 14:34:23 +08:00
|
|
|
static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip,
|
|
|
|
unsigned offset, int value)
|
|
|
|
{
|
|
|
|
sunxi_pinctrl_gpio_set(chip, offset, value);
|
|
|
|
return pinctrl_gpio_direction_output(chip->base + offset);
|
|
|
|
}
|
|
|
|
|
2013-02-03 19:10:11 +08:00
|
|
|
static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
|
|
|
|
const struct of_phandle_args *gpiospec,
|
|
|
|
u32 *flags)
|
|
|
|
{
|
|
|
|
int pin, base;
|
|
|
|
|
|
|
|
base = PINS_PER_BANK * gpiospec->args[0];
|
|
|
|
pin = base + gpiospec->args[1];
|
|
|
|
|
2014-07-15 01:24:37 +08:00
|
|
|
if (pin > gc->ngpio)
|
2013-02-03 19:10:11 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (flags)
|
|
|
|
*flags = gpiospec->args[2];
|
|
|
|
|
|
|
|
return pin;
|
|
|
|
}
|
|
|
|
|
2013-06-08 18:05:44 +08:00
|
|
|
static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
|
|
{
|
2015-12-09 05:40:43 +08:00
|
|
|
struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
|
2013-06-08 18:05:44 +08:00
|
|
|
struct sunxi_desc_function *desc;
|
2014-07-15 01:24:37 +08:00
|
|
|
unsigned pinnum = pctl->desc->pin_base + offset;
|
2014-07-01 00:04:59 +08:00
|
|
|
unsigned irqnum;
|
2013-06-08 18:05:44 +08:00
|
|
|
|
2013-08-30 16:31:25 +08:00
|
|
|
if (offset >= chip->ngpio)
|
2013-06-08 18:05:44 +08:00
|
|
|
return -ENXIO;
|
|
|
|
|
2014-07-15 01:24:37 +08:00
|
|
|
desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pinnum, "irq");
|
2013-06-08 18:05:44 +08:00
|
|
|
if (!desc)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-07-01 00:04:59 +08:00
|
|
|
irqnum = desc->irqbank * IRQ_PER_BANK + desc->irqnum;
|
|
|
|
|
2015-11-04 16:56:26 +08:00
|
|
|
dev_dbg(chip->parent, "%s: request IRQ for GPIO %d, return %d\n",
|
2014-07-01 00:04:59 +08:00
|
|
|
chip->label, offset + chip->base, irqnum);
|
2013-06-08 18:05:44 +08:00
|
|
|
|
2014-07-01 00:04:59 +08:00
|
|
|
return irq_find_mapping(pctl->domain, irqnum);
|
2013-06-08 18:05:44 +08:00
|
|
|
}
|
|
|
|
|
2014-06-29 22:11:00 +08:00
|
|
|
static int sunxi_pinctrl_irq_request_resources(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
|
|
|
struct sunxi_desc_function *func;
|
2014-07-15 01:24:36 +08:00
|
|
|
int ret;
|
2014-06-29 22:11:00 +08:00
|
|
|
|
|
|
|
func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
|
|
|
|
pctl->irq_array[d->hwirq], "irq");
|
|
|
|
if (!func)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-10-23 16:27:07 +08:00
|
|
|
ret = gpiochip_lock_as_irq(pctl->chip,
|
2014-07-15 01:24:37 +08:00
|
|
|
pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
|
2014-07-15 01:24:36 +08:00
|
|
|
if (ret) {
|
|
|
|
dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n",
|
|
|
|
irqd_to_hwirq(d));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-06-29 22:11:00 +08:00
|
|
|
/* Change muxing to INT mode */
|
|
|
|
sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
|
2013-01-29 04:33:12 +08:00
|
|
|
|
2014-06-29 22:11:00 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2013-01-29 04:33:12 +08:00
|
|
|
|
2014-07-15 01:24:36 +08:00
|
|
|
static void sunxi_pinctrl_irq_release_resources(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
|
|
|
|
2014-10-23 16:27:07 +08:00
|
|
|
gpiochip_unlock_as_irq(pctl->chip,
|
|
|
|
pctl->irq_array[d->hwirq] - pctl->desc->pin_base);
|
2014-07-15 01:24:36 +08:00
|
|
|
}
|
|
|
|
|
2014-06-29 22:11:01 +08:00
|
|
|
static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type)
|
2013-06-08 18:05:44 +08:00
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
2018-03-16 22:02:07 +08:00
|
|
|
u32 reg = sunxi_irq_cfg_reg(pctl->desc, d->hwirq);
|
2013-06-08 18:05:44 +08:00
|
|
|
u8 index = sunxi_irq_cfg_offset(d->hwirq);
|
2013-08-04 18:38:48 +08:00
|
|
|
unsigned long flags;
|
2013-08-04 18:38:47 +08:00
|
|
|
u32 regval;
|
2013-06-08 18:05:44 +08:00
|
|
|
u8 mode;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case IRQ_TYPE_EDGE_RISING:
|
|
|
|
mode = IRQ_EDGE_RISING;
|
|
|
|
break;
|
|
|
|
case IRQ_TYPE_EDGE_FALLING:
|
|
|
|
mode = IRQ_EDGE_FALLING;
|
|
|
|
break;
|
|
|
|
case IRQ_TYPE_EDGE_BOTH:
|
|
|
|
mode = IRQ_EDGE_BOTH;
|
|
|
|
break;
|
|
|
|
case IRQ_TYPE_LEVEL_HIGH:
|
|
|
|
mode = IRQ_LEVEL_HIGH;
|
|
|
|
break;
|
|
|
|
case IRQ_TYPE_LEVEL_LOW:
|
|
|
|
mode = IRQ_LEVEL_LOW;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_lock_irqsave(&pctl->lock, flags);
|
2013-08-04 18:38:48 +08:00
|
|
|
|
2015-07-20 20:41:11 +08:00
|
|
|
if (type & IRQ_TYPE_LEVEL_MASK)
|
2015-09-16 18:32:40 +08:00
|
|
|
irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_level_irq_chip,
|
|
|
|
handle_fasteoi_irq, NULL);
|
2015-07-20 20:41:11 +08:00
|
|
|
else
|
2015-09-16 18:32:40 +08:00
|
|
|
irq_set_chip_handler_name_locked(d, &sunxi_pinctrl_edge_irq_chip,
|
|
|
|
handle_edge_irq, NULL);
|
2015-07-20 20:41:11 +08:00
|
|
|
|
2013-08-04 18:38:47 +08:00
|
|
|
regval = readl(pctl->membase + reg);
|
2014-02-18 05:19:43 +08:00
|
|
|
regval &= ~(IRQ_CFG_IRQ_MASK << index);
|
2013-08-04 18:38:47 +08:00
|
|
|
writel(regval | (mode << index), pctl->membase + reg);
|
2013-06-08 18:05:44 +08:00
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_unlock_irqrestore(&pctl->lock, flags);
|
2013-06-08 18:05:44 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-06-05 21:26:00 +08:00
|
|
|
static void sunxi_pinctrl_irq_ack(struct irq_data *d)
|
2013-06-08 18:05:44 +08:00
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
2018-03-16 22:02:07 +08:00
|
|
|
u32 status_reg = sunxi_irq_status_reg(pctl->desc, d->hwirq);
|
2013-06-08 18:05:44 +08:00
|
|
|
u8 status_idx = sunxi_irq_status_offset(d->hwirq);
|
|
|
|
|
|
|
|
/* Clear the IRQ */
|
|
|
|
writel(1 << status_idx, pctl->membase + status_reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sunxi_pinctrl_irq_mask(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
2018-03-16 22:02:07 +08:00
|
|
|
u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq);
|
2013-06-08 18:05:44 +08:00
|
|
|
u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
|
2013-08-04 18:38:48 +08:00
|
|
|
unsigned long flags;
|
2013-06-08 18:05:44 +08:00
|
|
|
u32 val;
|
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_lock_irqsave(&pctl->lock, flags);
|
2013-08-04 18:38:48 +08:00
|
|
|
|
2013-06-08 18:05:44 +08:00
|
|
|
/* Mask the IRQ */
|
|
|
|
val = readl(pctl->membase + reg);
|
|
|
|
writel(val & ~(1 << idx), pctl->membase + reg);
|
2013-08-04 18:38:48 +08:00
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_unlock_irqrestore(&pctl->lock, flags);
|
2013-06-08 18:05:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
|
2018-03-16 22:02:07 +08:00
|
|
|
u32 reg = sunxi_irq_ctrl_reg(pctl->desc, d->hwirq);
|
2013-06-08 18:05:44 +08:00
|
|
|
u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
|
2013-08-04 18:38:48 +08:00
|
|
|
unsigned long flags;
|
2013-06-08 18:05:44 +08:00
|
|
|
u32 val;
|
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_lock_irqsave(&pctl->lock, flags);
|
2013-08-04 18:38:48 +08:00
|
|
|
|
2013-06-08 18:05:44 +08:00
|
|
|
/* Unmask the IRQ */
|
|
|
|
val = readl(pctl->membase + reg);
|
|
|
|
writel(val | (1 << idx), pctl->membase + reg);
|
2013-08-04 18:38:48 +08:00
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_unlock_irqrestore(&pctl->lock, flags);
|
2013-06-08 18:05:44 +08:00
|
|
|
}
|
|
|
|
|
2014-06-29 22:11:02 +08:00
|
|
|
static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d)
|
|
|
|
{
|
|
|
|
sunxi_pinctrl_irq_ack(d);
|
|
|
|
sunxi_pinctrl_irq_unmask(d);
|
|
|
|
}
|
|
|
|
|
2014-06-29 22:11:01 +08:00
|
|
|
static struct irq_chip sunxi_pinctrl_edge_irq_chip = {
|
2015-07-20 20:41:12 +08:00
|
|
|
.name = "sunxi_pio_edge",
|
2014-06-05 21:26:00 +08:00
|
|
|
.irq_ack = sunxi_pinctrl_irq_ack,
|
2013-06-08 18:05:44 +08:00
|
|
|
.irq_mask = sunxi_pinctrl_irq_mask,
|
|
|
|
.irq_unmask = sunxi_pinctrl_irq_unmask,
|
2014-06-29 22:11:00 +08:00
|
|
|
.irq_request_resources = sunxi_pinctrl_irq_request_resources,
|
2014-07-15 01:24:36 +08:00
|
|
|
.irq_release_resources = sunxi_pinctrl_irq_release_resources,
|
2013-06-08 18:05:44 +08:00
|
|
|
.irq_set_type = sunxi_pinctrl_irq_set_type,
|
2014-06-29 22:10:59 +08:00
|
|
|
.flags = IRQCHIP_SKIP_SET_WAKE,
|
2013-06-08 18:05:44 +08:00
|
|
|
};
|
|
|
|
|
2014-06-29 22:11:01 +08:00
|
|
|
static struct irq_chip sunxi_pinctrl_level_irq_chip = {
|
2015-07-20 20:41:12 +08:00
|
|
|
.name = "sunxi_pio_level",
|
2014-06-29 22:11:01 +08:00
|
|
|
.irq_eoi = sunxi_pinctrl_irq_ack,
|
2013-06-08 18:05:44 +08:00
|
|
|
.irq_mask = sunxi_pinctrl_irq_mask,
|
|
|
|
.irq_unmask = sunxi_pinctrl_irq_unmask,
|
2014-06-29 22:11:02 +08:00
|
|
|
/* Define irq_enable / disable to avoid spurious irqs for drivers
|
|
|
|
* using these to suppress irqs while they clear the irq source */
|
|
|
|
.irq_enable = sunxi_pinctrl_irq_ack_unmask,
|
|
|
|
.irq_disable = sunxi_pinctrl_irq_mask,
|
2014-06-29 22:11:01 +08:00
|
|
|
.irq_request_resources = sunxi_pinctrl_irq_request_resources,
|
2014-07-15 01:24:36 +08:00
|
|
|
.irq_release_resources = sunxi_pinctrl_irq_release_resources,
|
2013-06-08 18:05:44 +08:00
|
|
|
.irq_set_type = sunxi_pinctrl_irq_set_type,
|
2014-06-29 22:11:01 +08:00
|
|
|
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_EOI_THREADED |
|
|
|
|
IRQCHIP_EOI_IF_HANDLED,
|
2013-06-08 18:05:44 +08:00
|
|
|
};
|
|
|
|
|
2015-07-27 20:41:57 +08:00
|
|
|
static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d,
|
|
|
|
struct device_node *node,
|
|
|
|
const u32 *intspec,
|
|
|
|
unsigned int intsize,
|
|
|
|
unsigned long *out_hwirq,
|
|
|
|
unsigned int *out_type)
|
|
|
|
{
|
2015-10-16 15:46:11 +08:00
|
|
|
struct sunxi_pinctrl *pctl = d->host_data;
|
2015-07-27 20:41:57 +08:00
|
|
|
struct sunxi_desc_function *desc;
|
|
|
|
int pin, base;
|
|
|
|
|
|
|
|
if (intsize < 3)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
base = PINS_PER_BANK * intspec[0];
|
2015-10-16 15:46:11 +08:00
|
|
|
pin = pctl->desc->pin_base + base + intspec[1];
|
2015-07-27 20:41:57 +08:00
|
|
|
|
2015-10-16 15:46:11 +08:00
|
|
|
desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, pin, "irq");
|
2015-07-27 20:41:57 +08:00
|
|
|
if (!desc)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
*out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum;
|
|
|
|
*out_type = intspec[2];
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-06-02 19:29:58 +08:00
|
|
|
static const struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = {
|
2015-07-27 20:41:57 +08:00
|
|
|
.xlate = sunxi_pinctrl_irq_of_xlate,
|
|
|
|
};
|
|
|
|
|
2015-09-14 16:42:37 +08:00
|
|
|
static void sunxi_pinctrl_irq_handler(struct irq_desc *desc)
|
2013-06-08 18:05:44 +08:00
|
|
|
{
|
2015-07-13 07:55:27 +08:00
|
|
|
unsigned int irq = irq_desc_get_irq(desc);
|
2015-06-04 12:13:16 +08:00
|
|
|
struct irq_chip *chip = irq_desc_get_chip(desc);
|
|
|
|
struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc);
|
2014-06-05 21:26:04 +08:00
|
|
|
unsigned long bank, reg, val;
|
|
|
|
|
|
|
|
for (bank = 0; bank < pctl->desc->irq_banks; bank++)
|
|
|
|
if (irq == pctl->irq[bank])
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (bank == pctl->desc->irq_banks)
|
|
|
|
return;
|
2013-06-08 18:05:44 +08:00
|
|
|
|
2018-03-16 22:02:07 +08:00
|
|
|
reg = sunxi_irq_status_reg_from_bank(pctl->desc, bank);
|
2014-06-05 21:26:04 +08:00
|
|
|
val = readl(pctl->membase + reg);
|
2013-06-08 18:05:44 +08:00
|
|
|
|
2014-06-05 21:26:04 +08:00
|
|
|
if (val) {
|
2013-06-08 18:05:44 +08:00
|
|
|
int irqoffset;
|
|
|
|
|
2014-02-11 00:22:37 +08:00
|
|
|
chained_irq_enter(chip, desc);
|
2014-06-05 21:26:04 +08:00
|
|
|
for_each_set_bit(irqoffset, &val, IRQ_PER_BANK) {
|
|
|
|
int pin_irq = irq_find_mapping(pctl->domain,
|
|
|
|
bank * IRQ_PER_BANK + irqoffset);
|
2013-06-08 18:05:44 +08:00
|
|
|
generic_handle_irq(pin_irq);
|
|
|
|
}
|
2014-02-11 00:22:37 +08:00
|
|
|
chained_irq_exit(chip, desc);
|
2013-06-08 18:05:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl_function *func = pctl->functions;
|
|
|
|
|
|
|
|
while (func->name) {
|
|
|
|
/* function already there */
|
|
|
|
if (strcmp(func->name, name) == 0) {
|
|
|
|
func->ngroups++;
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
func++;
|
|
|
|
}
|
|
|
|
|
|
|
|
func->name = name;
|
|
|
|
func->ngroups = 1;
|
|
|
|
|
|
|
|
pctl->nfunctions++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sunxi_pinctrl_build_state(struct platform_device *pdev)
|
|
|
|
{
|
|
|
|
struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
|
2018-10-16 14:22:28 +08:00
|
|
|
void *ptr;
|
2013-01-19 05:30:34 +08:00
|
|
|
int i;
|
|
|
|
|
2017-01-09 05:31:15 +08:00
|
|
|
/*
|
|
|
|
* Allocate groups
|
|
|
|
*
|
|
|
|
* We assume that the number of groups is the number of pins
|
|
|
|
* given in the data array.
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2017-01-09 05:31:15 +08:00
|
|
|
* This will not always be true, since some pins might not be
|
|
|
|
* available in the current variant, but fortunately for us,
|
|
|
|
* this means that the number of pins is the maximum group
|
|
|
|
* number we will ever see.
|
|
|
|
*/
|
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 05:07:58 +08:00
|
|
|
pctl->groups = devm_kcalloc(&pdev->dev,
|
|
|
|
pctl->desc->npins, sizeof(*pctl->groups),
|
2013-01-19 05:30:34 +08:00
|
|
|
GFP_KERNEL);
|
|
|
|
if (!pctl->groups)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
for (i = 0; i < pctl->desc->npins; i++) {
|
|
|
|
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
|
2017-01-09 05:31:15 +08:00
|
|
|
struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups;
|
|
|
|
|
|
|
|
if (pin->variant && !(pctl->variant & pin->variant))
|
|
|
|
continue;
|
2013-01-19 05:30:34 +08:00
|
|
|
|
|
|
|
group->name = pin->pin.name;
|
|
|
|
group->pin = pin->pin.number;
|
2017-01-09 05:31:15 +08:00
|
|
|
|
|
|
|
/* And now we count the actual number of pins / groups */
|
|
|
|
pctl->ngroups++;
|
2013-01-19 05:30:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We suppose that we won't have any more functions than pins,
|
|
|
|
* we'll reallocate that later anyway
|
|
|
|
*/
|
2018-09-21 09:59:41 +08:00
|
|
|
pctl->functions = kcalloc(pctl->ngroups,
|
|
|
|
sizeof(*pctl->functions),
|
|
|
|
GFP_KERNEL);
|
2013-01-19 05:30:34 +08:00
|
|
|
if (!pctl->functions)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* Count functions and their associated groups */
|
|
|
|
for (i = 0; i < pctl->desc->npins; i++) {
|
|
|
|
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
|
2017-01-09 05:31:15 +08:00
|
|
|
struct sunxi_desc_function *func;
|
|
|
|
|
|
|
|
if (pin->variant && !(pctl->variant & pin->variant))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (func = pin->functions; func->name; func++) {
|
|
|
|
if (func->variant && !(pctl->variant & func->variant))
|
|
|
|
continue;
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2014-05-26 15:47:56 +08:00
|
|
|
/* Create interrupt mapping while we're at it */
|
2014-06-05 21:26:04 +08:00
|
|
|
if (!strcmp(func->name, "irq")) {
|
|
|
|
int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK;
|
|
|
|
pctl->irq_array[irqnum] = pin->pin.number;
|
|
|
|
}
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
sunxi_pinctrl_add_function(pctl, func->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-09 05:31:15 +08:00
|
|
|
/* And now allocated and fill the array for real */
|
2018-10-16 14:22:28 +08:00
|
|
|
ptr = krealloc(pctl->functions,
|
|
|
|
pctl->nfunctions * sizeof(*pctl->functions),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!ptr) {
|
2017-01-09 05:31:15 +08:00
|
|
|
kfree(pctl->functions);
|
2018-10-16 14:22:28 +08:00
|
|
|
pctl->functions = NULL;
|
2017-01-09 05:31:15 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2018-10-16 14:22:28 +08:00
|
|
|
pctl->functions = ptr;
|
2013-01-19 05:30:34 +08:00
|
|
|
|
|
|
|
for (i = 0; i < pctl->desc->npins; i++) {
|
|
|
|
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
|
2017-01-09 05:31:15 +08:00
|
|
|
struct sunxi_desc_function *func;
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2017-01-09 05:31:15 +08:00
|
|
|
if (pin->variant && !(pctl->variant & pin->variant))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (func = pin->functions; func->name; func++) {
|
2013-01-19 05:30:34 +08:00
|
|
|
struct sunxi_pinctrl_function *func_item;
|
|
|
|
const char **func_grp;
|
|
|
|
|
2017-01-09 05:31:15 +08:00
|
|
|
if (func->variant && !(pctl->variant & func->variant))
|
|
|
|
continue;
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
func_item = sunxi_pinctrl_find_function_by_name(pctl,
|
|
|
|
func->name);
|
2018-09-21 09:59:41 +08:00
|
|
|
if (!func_item) {
|
|
|
|
kfree(pctl->functions);
|
2013-01-19 05:30:34 +08:00
|
|
|
return -EINVAL;
|
2018-09-21 09:59:41 +08:00
|
|
|
}
|
2013-01-19 05:30:34 +08:00
|
|
|
|
|
|
|
if (!func_item->groups) {
|
|
|
|
func_item->groups =
|
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 05:07:58 +08:00
|
|
|
devm_kcalloc(&pdev->dev,
|
|
|
|
func_item->ngroups,
|
|
|
|
sizeof(*func_item->groups),
|
2013-01-19 05:30:34 +08:00
|
|
|
GFP_KERNEL);
|
2018-09-21 09:59:41 +08:00
|
|
|
if (!func_item->groups) {
|
|
|
|
kfree(pctl->functions);
|
2013-01-19 05:30:34 +08:00
|
|
|
return -ENOMEM;
|
2018-09-21 09:59:41 +08:00
|
|
|
}
|
2013-01-19 05:30:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func_grp = func_item->groups;
|
|
|
|
while (*func_grp)
|
|
|
|
func_grp++;
|
|
|
|
|
|
|
|
*func_grp = pin->pin.name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-15 04:53:03 +08:00
|
|
|
static int sunxi_pinctrl_get_debounce_div(struct clk *clk, int freq, int *diff)
|
|
|
|
{
|
|
|
|
unsigned long clock = clk_get_rate(clk);
|
2016-11-16 22:18:18 +08:00
|
|
|
unsigned int best_diff, best_div;
|
2016-11-15 04:53:03 +08:00
|
|
|
int i;
|
|
|
|
|
2016-11-16 22:18:18 +08:00
|
|
|
best_diff = abs(freq - clock);
|
|
|
|
best_div = 0;
|
|
|
|
|
|
|
|
for (i = 1; i < 8; i++) {
|
2016-11-15 04:53:03 +08:00
|
|
|
int cur_diff = abs(freq - (clock >> i));
|
|
|
|
|
|
|
|
if (cur_diff < best_diff) {
|
|
|
|
best_diff = cur_diff;
|
|
|
|
best_div = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*diff = best_diff;
|
|
|
|
return best_div;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
|
|
|
|
struct device_node *node)
|
|
|
|
{
|
|
|
|
unsigned int hosc_diff, losc_diff;
|
|
|
|
unsigned int hosc_div, losc_div;
|
|
|
|
struct clk *hosc, *losc;
|
|
|
|
u8 div, src;
|
|
|
|
int i, ret;
|
|
|
|
|
|
|
|
/* Deal with old DTs that didn't have the oscillators */
|
2018-01-19 23:18:19 +08:00
|
|
|
if (of_clk_get_parent_count(node) != 3)
|
2016-11-15 04:53:03 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* If we don't have any setup, bail out */
|
|
|
|
if (!of_find_property(node, "input-debounce", NULL))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
losc = devm_clk_get(pctl->dev, "losc");
|
|
|
|
if (IS_ERR(losc))
|
|
|
|
return PTR_ERR(losc);
|
|
|
|
|
|
|
|
hosc = devm_clk_get(pctl->dev, "hosc");
|
|
|
|
if (IS_ERR(hosc))
|
|
|
|
return PTR_ERR(hosc);
|
|
|
|
|
|
|
|
for (i = 0; i < pctl->desc->irq_banks; i++) {
|
|
|
|
unsigned long debounce_freq;
|
|
|
|
u32 debounce;
|
|
|
|
|
|
|
|
ret = of_property_read_u32_index(node, "input-debounce",
|
|
|
|
i, &debounce);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (!debounce)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce);
|
|
|
|
losc_div = sunxi_pinctrl_get_debounce_div(losc,
|
|
|
|
debounce_freq,
|
|
|
|
&losc_diff);
|
|
|
|
|
|
|
|
hosc_div = sunxi_pinctrl_get_debounce_div(hosc,
|
|
|
|
debounce_freq,
|
|
|
|
&hosc_diff);
|
|
|
|
|
|
|
|
if (hosc_diff < losc_diff) {
|
|
|
|
div = hosc_div;
|
|
|
|
src = 1;
|
|
|
|
} else {
|
|
|
|
div = losc_div;
|
|
|
|
src = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
writel(src | div << 4,
|
|
|
|
pctl->membase +
|
2018-03-16 22:02:07 +08:00
|
|
|
sunxi_irq_debounce_reg_from_bank(pctl->desc, i));
|
2016-11-15 04:53:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-01-09 05:31:15 +08:00
|
|
|
int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
|
|
|
|
const struct sunxi_pinctrl_desc *desc,
|
|
|
|
unsigned long variant)
|
2013-01-19 05:30:34 +08:00
|
|
|
{
|
|
|
|
struct device_node *node = pdev->dev.of_node;
|
2014-05-22 22:25:27 +08:00
|
|
|
struct pinctrl_desc *pctrl_desc;
|
2013-01-19 05:30:34 +08:00
|
|
|
struct pinctrl_pin_desc *pins;
|
|
|
|
struct sunxi_pinctrl *pctl;
|
2017-10-10 04:53:37 +08:00
|
|
|
struct pinmux_ops *pmxops;
|
2014-04-27 03:59:50 +08:00
|
|
|
struct resource *res;
|
2017-01-09 05:31:15 +08:00
|
|
|
int i, ret, last_pin, pin_idx;
|
2013-03-22 22:20:40 +08:00
|
|
|
struct clk *clk;
|
2013-01-19 05:30:34 +08:00
|
|
|
|
|
|
|
pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
|
|
|
|
if (!pctl)
|
|
|
|
return -ENOMEM;
|
|
|
|
platform_set_drvdata(pdev, pctl);
|
|
|
|
|
2017-03-10 00:22:06 +08:00
|
|
|
raw_spin_lock_init(&pctl->lock);
|
2013-08-04 18:38:48 +08:00
|
|
|
|
2014-04-27 03:59:50 +08:00
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
|
pctl->membase = devm_ioremap_resource(&pdev->dev, res);
|
|
|
|
if (IS_ERR(pctl->membase))
|
|
|
|
return PTR_ERR(pctl->membase);
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2014-05-22 22:25:27 +08:00
|
|
|
pctl->dev = &pdev->dev;
|
2014-04-19 02:10:41 +08:00
|
|
|
pctl->desc = desc;
|
2017-01-09 05:31:15 +08:00
|
|
|
pctl->variant = variant;
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2014-06-05 21:26:04 +08:00
|
|
|
pctl->irq_array = devm_kcalloc(&pdev->dev,
|
|
|
|
IRQ_PER_BANK * pctl->desc->irq_banks,
|
|
|
|
sizeof(*pctl->irq_array),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!pctl->irq_array)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-01-19 05:30:34 +08:00
|
|
|
ret = sunxi_pinctrl_build_state(pdev);
|
|
|
|
if (ret) {
|
|
|
|
dev_err(&pdev->dev, "dt probe failed: %d\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
treewide: devm_kzalloc() -> devm_kcalloc()
The devm_kzalloc() function has a 2-factor argument form, devm_kcalloc().
This patch replaces cases of:
devm_kzalloc(handle, a * b, gfp)
with:
devm_kcalloc(handle, a * b, gfp)
as well as handling cases of:
devm_kzalloc(handle, a * b * c, gfp)
with:
devm_kzalloc(handle, array3_size(a, b, c), gfp)
as it's slightly less ugly than:
devm_kcalloc(handle, array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
devm_kzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
Some manual whitespace fixes were needed in this patch, as Coccinelle
really liked to write "=devm_kcalloc..." instead of "= devm_kcalloc...".
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
devm_kzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
devm_kzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
devm_kzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
devm_kzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
devm_kzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE,
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
devm_kzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression HANDLE;
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
devm_kzalloc(HANDLE, sizeof(THING) * C2, ...)
|
devm_kzalloc(HANDLE, sizeof(TYPE) * C2, ...)
|
devm_kzalloc(HANDLE, C1 * C2 * C3, ...)
|
devm_kzalloc(HANDLE, C1 * C2, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * E2
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- (E1) * (E2)
+ E1, E2
, ...)
|
- devm_kzalloc
+ devm_kcalloc
(HANDLE,
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 05:07:58 +08:00
|
|
|
pins = devm_kcalloc(&pdev->dev,
|
|
|
|
pctl->desc->npins, sizeof(*pins),
|
2013-01-19 05:30:34 +08:00
|
|
|
GFP_KERNEL);
|
|
|
|
if (!pins)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-01-09 05:31:15 +08:00
|
|
|
for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) {
|
|
|
|
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
|
|
|
|
|
|
|
|
if (pin->variant && !(pctl->variant & pin->variant))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pins[pin_idx++] = pin->pin;
|
|
|
|
}
|
2013-01-19 05:30:34 +08:00
|
|
|
|
2014-05-22 22:25:27 +08:00
|
|
|
pctrl_desc = devm_kzalloc(&pdev->dev,
|
|
|
|
sizeof(*pctrl_desc),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!pctrl_desc)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
pctrl_desc->name = dev_name(&pdev->dev);
|
|
|
|
pctrl_desc->owner = THIS_MODULE;
|
|
|
|
pctrl_desc->pins = pins;
|
2017-01-09 05:31:15 +08:00
|
|
|
pctrl_desc->npins = pctl->ngroups;
|
2014-05-22 22:25:27 +08:00
|
|
|
pctrl_desc->confops = &sunxi_pconf_ops;
|
|
|
|
pctrl_desc->pctlops = &sunxi_pctrl_ops;
|
2017-10-10 04:53:37 +08:00
|
|
|
|
|
|
|
pmxops = devm_kmemdup(&pdev->dev, &sunxi_pmx_ops, sizeof(sunxi_pmx_ops),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!pmxops)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (desc->disable_strict_mode)
|
|
|
|
pmxops->strict = false;
|
|
|
|
|
|
|
|
pctrl_desc->pmxops = pmxops;
|
2014-05-22 22:25:27 +08:00
|
|
|
|
2016-02-24 17:14:07 +08:00
|
|
|
pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl);
|
2015-06-09 12:01:16 +08:00
|
|
|
if (IS_ERR(pctl->pctl_dev)) {
|
2013-01-19 05:30:34 +08:00
|
|
|
dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
|
2015-06-09 12:01:16 +08:00
|
|
|
return PTR_ERR(pctl->pctl_dev);
|
2013-01-19 05:30:34 +08:00
|
|
|
}
|
|
|
|
|
2013-01-29 04:33:12 +08:00
|
|
|
pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
|
2016-02-24 17:14:07 +08:00
|
|
|
if (!pctl->chip)
|
|
|
|
return -ENOMEM;
|
2013-01-29 04:33:12 +08:00
|
|
|
|
|
|
|
last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number;
|
2014-04-10 21:52:43 +08:00
|
|
|
pctl->chip->owner = THIS_MODULE;
|
2019-03-15 03:32:52 +08:00
|
|
|
pctl->chip->request = gpiochip_generic_request;
|
|
|
|
pctl->chip->free = gpiochip_generic_free;
|
2019-03-15 03:32:53 +08:00
|
|
|
pctl->chip->set_config = gpiochip_generic_config;
|
2019-03-15 03:32:52 +08:00
|
|
|
pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input;
|
|
|
|
pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output;
|
|
|
|
pctl->chip->get = sunxi_pinctrl_gpio_get;
|
|
|
|
pctl->chip->set = sunxi_pinctrl_gpio_set;
|
|
|
|
pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate;
|
|
|
|
pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq;
|
|
|
|
pctl->chip->of_gpio_n_cells = 3;
|
|
|
|
pctl->chip->can_sleep = false;
|
2014-04-10 21:52:43 +08:00
|
|
|
pctl->chip->ngpio = round_up(last_pin, PINS_PER_BANK) -
|
|
|
|
pctl->desc->pin_base;
|
2013-01-29 04:33:12 +08:00
|
|
|
pctl->chip->label = dev_name(&pdev->dev);
|
2015-11-04 16:56:26 +08:00
|
|
|
pctl->chip->parent = &pdev->dev;
|
2014-04-10 21:52:43 +08:00
|
|
|
pctl->chip->base = pctl->desc->pin_base;
|
2013-01-29 04:33:12 +08:00
|
|
|
|
2015-12-09 05:40:43 +08:00
|
|
|
ret = gpiochip_add_data(pctl->chip, pctl);
|
2013-01-29 04:33:12 +08:00
|
|
|
if (ret)
|
2016-02-24 17:14:07 +08:00
|
|
|
return ret;
|
2013-01-29 04:33:12 +08:00
|
|
|
|
|
|
|
for (i = 0; i < pctl->desc->npins; i++) {
|
|
|
|
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
|
|
|
|
|
|
|
|
ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
|
2014-07-15 01:24:37 +08:00
|
|
|
pin->pin.number - pctl->desc->pin_base,
|
2013-01-29 04:33:12 +08:00
|
|
|
pin->pin.number, 1);
|
|
|
|
if (ret)
|
|
|
|
goto gpiochip_error;
|
|
|
|
}
|
|
|
|
|
2018-04-18 22:50:05 +08:00
|
|
|
ret = of_clk_get_parent_count(node);
|
2018-03-03 20:25:54 +08:00
|
|
|
clk = devm_clk_get(&pdev->dev, ret == 1 ? NULL : "apb");
|
2013-05-23 17:32:14 +08:00
|
|
|
if (IS_ERR(clk)) {
|
|
|
|
ret = PTR_ERR(clk);
|
2013-03-22 22:20:40 +08:00
|
|
|
goto gpiochip_error;
|
2013-05-23 17:32:14 +08:00
|
|
|
}
|
2013-03-22 22:20:40 +08:00
|
|
|
|
2014-04-10 21:52:40 +08:00
|
|
|
ret = clk_prepare_enable(clk);
|
|
|
|
if (ret)
|
|
|
|
goto gpiochip_error;
|
2013-03-22 22:20:40 +08:00
|
|
|
|
2014-06-05 21:26:04 +08:00
|
|
|
pctl->irq = devm_kcalloc(&pdev->dev,
|
|
|
|
pctl->desc->irq_banks,
|
|
|
|
sizeof(*pctl->irq),
|
|
|
|
GFP_KERNEL);
|
2013-06-08 18:05:44 +08:00
|
|
|
if (!pctl->irq) {
|
2014-06-05 21:26:04 +08:00
|
|
|
ret = -ENOMEM;
|
2014-04-27 04:28:54 +08:00
|
|
|
goto clk_error;
|
2013-06-08 18:05:44 +08:00
|
|
|
}
|
|
|
|
|
2014-06-05 21:26:04 +08:00
|
|
|
for (i = 0; i < pctl->desc->irq_banks; i++) {
|
|
|
|
pctl->irq[i] = platform_get_irq(pdev, i);
|
|
|
|
if (pctl->irq[i] < 0) {
|
|
|
|
ret = pctl->irq[i];
|
|
|
|
goto clk_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pctl->domain = irq_domain_add_linear(node,
|
|
|
|
pctl->desc->irq_banks * IRQ_PER_BANK,
|
2015-07-27 20:41:57 +08:00
|
|
|
&sunxi_pinctrl_irq_domain_ops,
|
|
|
|
pctl);
|
2013-06-08 18:05:44 +08:00
|
|
|
if (!pctl->domain) {
|
|
|
|
dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
|
|
|
|
ret = -ENOMEM;
|
2014-04-27 04:28:54 +08:00
|
|
|
goto clk_error;
|
2013-06-08 18:05:44 +08:00
|
|
|
}
|
|
|
|
|
2014-06-05 21:26:04 +08:00
|
|
|
for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) {
|
2013-06-08 18:05:44 +08:00
|
|
|
int irqno = irq_create_mapping(pctl->domain, i);
|
|
|
|
|
2014-06-29 22:11:01 +08:00
|
|
|
irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip,
|
|
|
|
handle_edge_irq);
|
2013-06-08 18:05:44 +08:00
|
|
|
irq_set_chip_data(irqno, pctl);
|
2015-09-16 16:28:29 +08:00
|
|
|
}
|
2013-06-08 18:05:44 +08:00
|
|
|
|
2014-06-05 21:26:04 +08:00
|
|
|
for (i = 0; i < pctl->desc->irq_banks; i++) {
|
2014-06-29 22:11:01 +08:00
|
|
|
/* Mask and clear all IRQs before registering a handler */
|
2018-03-16 22:02:07 +08:00
|
|
|
writel(0, pctl->membase +
|
|
|
|
sunxi_irq_ctrl_reg_from_bank(pctl->desc, i));
|
2014-06-29 22:11:01 +08:00
|
|
|
writel(0xffffffff,
|
2018-03-16 22:02:07 +08:00
|
|
|
pctl->membase +
|
|
|
|
sunxi_irq_status_reg_from_bank(pctl->desc, i));
|
2014-06-29 22:11:01 +08:00
|
|
|
|
pinctrl/sun4i: Fix race in installing chained IRQ handler
Fix a race where a pending interrupt could be received and the handler
called before the handler's data has been setup, by converting to
irq_set_chained_handler_and_data().
Search and conversion was done with coccinelle:
@@
expression E1, E2, E3;
@@
(
-if (irq_set_chained_handler(E1, E3) != 0)
- BUG();
|
-irq_set_chained_handler(E1, E3);
)
-irq_set_handler_data(E1, E2);
+irq_set_chained_handler_and_data(E1, E3, E2);
@@
expression E1, E2, E3;
@@
(
-if (irq_set_chained_handler(E1, E3) != 0)
- BUG();
...
|
-irq_set_chained_handler(E1, E3);
...
)
-irq_set_handler_data(E1, E2);
+irq_set_chained_handler_and_data(E1, E3, E2);
Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Julia Lawall <Julia.Lawall@lip6.fr>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Chen-Yu Tsai <wens@csie.org>
Cc: Fan Wu <fwu@marvell.com>
Cc: abdoulaye berthe <berthe.ab@gmail.com>
Cc: Alexandre Courbot <acourbot@nvidia.com>
Cc: linux-gpio@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
2015-06-22 02:16:18 +08:00
|
|
|
irq_set_chained_handler_and_data(pctl->irq[i],
|
|
|
|
sunxi_pinctrl_irq_handler,
|
|
|
|
pctl);
|
2014-06-05 21:26:04 +08:00
|
|
|
}
|
2013-06-08 18:05:44 +08:00
|
|
|
|
2016-11-15 04:53:03 +08:00
|
|
|
sunxi_pinctrl_setup_debounce(pctl, node);
|
|
|
|
|
2013-01-29 04:33:12 +08:00
|
|
|
dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
|
2013-01-19 05:30:34 +08:00
|
|
|
|
|
|
|
return 0;
|
2013-01-29 04:33:12 +08:00
|
|
|
|
2014-04-10 21:52:41 +08:00
|
|
|
clk_error:
|
|
|
|
clk_disable_unprepare(clk);
|
2013-01-29 04:33:12 +08:00
|
|
|
gpiochip_error:
|
2014-07-13 04:30:13 +08:00
|
|
|
gpiochip_remove(pctl->chip);
|
2013-01-29 04:33:12 +08:00
|
|
|
return ret;
|
2013-01-19 05:30:34 +08:00
|
|
|
}
|