The core support for the pinctrl drivers for all the UniPhier SoCs. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Reviewed-by: Simon Glass <sjg@chromium.org>master
parent
8a5f6129d1
commit
5dc626f836
@ -0,0 +1,6 @@ |
|||||||
|
if ARCH_UNIPHIER |
||||||
|
|
||||||
|
config PINCTRL_UNIPHIER_CORE |
||||||
|
bool |
||||||
|
|
||||||
|
endif |
@ -0,0 +1 @@ |
|||||||
|
obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o
|
@ -0,0 +1,154 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <common.h> |
||||||
|
#include <mapmem.h> |
||||||
|
#include <linux/io.h> |
||||||
|
#include <linux/err.h> |
||||||
|
#include <dm/device.h> |
||||||
|
#include <dm/pinctrl.h> |
||||||
|
|
||||||
|
#include "pinctrl-uniphier.h" |
||||||
|
|
||||||
|
DECLARE_GLOBAL_DATA_PTR; |
||||||
|
|
||||||
|
static int uniphier_pinctrl_get_groups_count(struct udevice *dev) |
||||||
|
{ |
||||||
|
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); |
||||||
|
|
||||||
|
return priv->socdata->groups_count; |
||||||
|
} |
||||||
|
|
||||||
|
static const char *uniphier_pinctrl_get_group_name(struct udevice *dev, |
||||||
|
unsigned selector) |
||||||
|
{ |
||||||
|
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); |
||||||
|
|
||||||
|
return priv->socdata->groups[selector].name; |
||||||
|
} |
||||||
|
|
||||||
|
static int uniphier_pinmux_get_functions_count(struct udevice *dev) |
||||||
|
{ |
||||||
|
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); |
||||||
|
|
||||||
|
return priv->socdata->functions_count; |
||||||
|
} |
||||||
|
|
||||||
|
static const char *uniphier_pinmux_get_function_name(struct udevice *dev, |
||||||
|
unsigned selector) |
||||||
|
{ |
||||||
|
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); |
||||||
|
|
||||||
|
return priv->socdata->functions[selector]; |
||||||
|
} |
||||||
|
|
||||||
|
static void uniphier_pinconf_input_enable(struct udevice *dev, unsigned pin) |
||||||
|
{ |
||||||
|
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); |
||||||
|
int pins_count = priv->socdata->pins_count; |
||||||
|
const struct uniphier_pinctrl_pin *pins = priv->socdata->pins; |
||||||
|
int i; |
||||||
|
|
||||||
|
for (i = 0; i < pins_count; i++) { |
||||||
|
if (pins[i].number == pin) { |
||||||
|
unsigned int iectrl; |
||||||
|
u32 tmp; |
||||||
|
|
||||||
|
iectrl = uniphier_pin_get_iectrl(pins[i].data); |
||||||
|
tmp = readl(priv->base + UNIPHIER_PINCTRL_IECTRL); |
||||||
|
tmp |= 1 << iectrl; |
||||||
|
writel(tmp, priv->base + UNIPHIER_PINCTRL_IECTRL); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void uniphier_pinmux_set_one(struct udevice *dev, unsigned pin, |
||||||
|
unsigned muxval) |
||||||
|
{ |
||||||
|
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); |
||||||
|
unsigned mux_bits = priv->socdata->mux_bits; |
||||||
|
unsigned reg_stride = priv->socdata->reg_stride; |
||||||
|
unsigned reg, reg_end, shift, mask; |
||||||
|
u32 tmp; |
||||||
|
|
||||||
|
reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; |
||||||
|
reg_end = reg + reg_stride; |
||||||
|
shift = pin * mux_bits % 32; |
||||||
|
mask = (1U << mux_bits) - 1; |
||||||
|
|
||||||
|
/*
|
||||||
|
* If reg_stride is greater than 4, the MSB of each pinsel shall be |
||||||
|
* stored in the offset+4. |
||||||
|
*/ |
||||||
|
for (; reg < reg_end; reg += 4) { |
||||||
|
tmp = readl(priv->base + reg); |
||||||
|
tmp &= ~(mask << shift); |
||||||
|
tmp |= (mask & muxval) << shift; |
||||||
|
writel(tmp, priv->base + reg); |
||||||
|
|
||||||
|
muxval >>= mux_bits; |
||||||
|
} |
||||||
|
|
||||||
|
if (priv->socdata->load_pinctrl) |
||||||
|
writel(1, priv->base + UNIPHIER_PINCTRL_LOAD_PINMUX); |
||||||
|
|
||||||
|
/* some pins need input-enabling */ |
||||||
|
uniphier_pinconf_input_enable(dev, pin); |
||||||
|
} |
||||||
|
|
||||||
|
static int uniphier_pinmux_group_set(struct udevice *dev, |
||||||
|
unsigned group_selector, |
||||||
|
unsigned func_selector) |
||||||
|
{ |
||||||
|
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); |
||||||
|
const struct uniphier_pinctrl_group *grp = |
||||||
|
&priv->socdata->groups[group_selector]; |
||||||
|
int i; |
||||||
|
|
||||||
|
for (i = 0; i < grp->num_pins; i++) |
||||||
|
uniphier_pinmux_set_one(dev, grp->pins[i], grp->muxvals[i]); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
const struct pinctrl_ops uniphier_pinctrl_ops = { |
||||||
|
.get_groups_count = uniphier_pinctrl_get_groups_count, |
||||||
|
.get_group_name = uniphier_pinctrl_get_group_name, |
||||||
|
.get_functions_count = uniphier_pinmux_get_functions_count, |
||||||
|
.get_function_name = uniphier_pinmux_get_function_name, |
||||||
|
.pinmux_group_set = uniphier_pinmux_group_set, |
||||||
|
.set_state = pinctrl_generic_set_state, |
||||||
|
}; |
||||||
|
|
||||||
|
int uniphier_pinctrl_probe(struct udevice *dev, |
||||||
|
struct uniphier_pinctrl_socdata *socdata) |
||||||
|
{ |
||||||
|
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); |
||||||
|
fdt_addr_t addr; |
||||||
|
fdt_size_t size; |
||||||
|
|
||||||
|
addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", |
||||||
|
&size); |
||||||
|
if (addr == FDT_ADDR_T_NONE) |
||||||
|
return -EINVAL; |
||||||
|
|
||||||
|
priv->base = map_sysmem(addr, size); |
||||||
|
if (!priv->base) |
||||||
|
return -ENOMEM; |
||||||
|
|
||||||
|
priv->socdata = socdata; |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int uniphier_pinctrl_remove(struct udevice *dev) |
||||||
|
{ |
||||||
|
struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); |
||||||
|
|
||||||
|
unmap_sysmem(priv->base); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,113 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: GPL-2.0+ |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef __PINCTRL_UNIPHIER_H__ |
||||||
|
#define __PINCTRL_UNIPHIER_H__ |
||||||
|
|
||||||
|
/* TODO: move this to include/linux/bug.h */ |
||||||
|
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) |
||||||
|
|
||||||
|
#include <linux/kernel.h> |
||||||
|
#include <linux/types.h> |
||||||
|
|
||||||
|
#define UNIPHIER_PINCTRL_PINMUX_BASE 0x0 |
||||||
|
#define UNIPHIER_PINCTRL_LOAD_PINMUX 0x700 |
||||||
|
#define UNIPHIER_PINCTRL_IECTRL 0xd00 |
||||||
|
|
||||||
|
#define UNIPHIER_PIN_ATTR_PACKED(iectrl) (iectrl) |
||||||
|
|
||||||
|
static inline unsigned int uniphier_pin_get_iectrl(unsigned long data) |
||||||
|
{ |
||||||
|
return data; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* struct uniphier_pinctrl_pin - pin data for UniPhier SoC |
||||||
|
* |
||||||
|
* @number: pin number |
||||||
|
* @data: additional per-pin data |
||||||
|
*/ |
||||||
|
struct uniphier_pinctrl_pin { |
||||||
|
unsigned number; |
||||||
|
unsigned long data; |
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* struct uniphier_pinctrl_group - pin group data for UniPhier SoC |
||||||
|
* |
||||||
|
* @name: pin group name |
||||||
|
* @pins: array of pins that belong to the group |
||||||
|
* @num_pins: number of pins in the group |
||||||
|
* @muxvals: array of values to be set to pinmux registers |
||||||
|
*/ |
||||||
|
struct uniphier_pinctrl_group { |
||||||
|
const char *name; |
||||||
|
const unsigned *pins; |
||||||
|
unsigned num_pins; |
||||||
|
const unsigned *muxvals; |
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* struct uniphier_pinctrl_socdata - SoC data for UniPhier pin controller |
||||||
|
* |
||||||
|
* @pins: array of pin data |
||||||
|
* @pins_count: number of pin data |
||||||
|
* @groups: array of pin group data |
||||||
|
* @groups_count: number of pin group data |
||||||
|
* @functions: array of pinmux function names |
||||||
|
* @functions_count: number of pinmux functions |
||||||
|
* @mux_bits: bit width of each pinmux register |
||||||
|
* @reg_stride: stride of pinmux register address |
||||||
|
* @load_pinctrl: if true, LOAD_PINMUX register must be set to one for new |
||||||
|
* values in pinmux registers to become really effective |
||||||
|
*/ |
||||||
|
struct uniphier_pinctrl_socdata { |
||||||
|
const struct uniphier_pinctrl_pin *pins; |
||||||
|
int pins_count; |
||||||
|
const struct uniphier_pinctrl_group *groups; |
||||||
|
int groups_count; |
||||||
|
const char * const *functions; |
||||||
|
int functions_count; |
||||||
|
unsigned mux_bits; |
||||||
|
unsigned reg_stride; |
||||||
|
bool load_pinctrl; |
||||||
|
}; |
||||||
|
|
||||||
|
#define UNIPHIER_PINCTRL_PIN(a, b) \ |
||||||
|
{ \
|
||||||
|
.number = a, \
|
||||||
|
.data = UNIPHIER_PIN_ATTR_PACKED(b), \
|
||||||
|
} |
||||||
|
|
||||||
|
#define UNIPHIER_PINCTRL_GROUP(grp) \ |
||||||
|
{ \
|
||||||
|
.name = #grp, \
|
||||||
|
.pins = grp##_pins, \
|
||||||
|
.num_pins = ARRAY_SIZE(grp##_pins), \
|
||||||
|
.muxvals = grp##_muxvals + \
|
||||||
|
BUILD_BUG_ON_ZERO(ARRAY_SIZE(grp##_pins) != \
|
||||||
|
ARRAY_SIZE(grp##_muxvals)), \
|
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* struct uniphier_pinctrl_priv - private data for UniPhier pinctrl driver |
||||||
|
* |
||||||
|
* @base: base address of the pinctrl device |
||||||
|
* @socdata: SoC specific data |
||||||
|
*/ |
||||||
|
struct uniphier_pinctrl_priv { |
||||||
|
void __iomem *base; |
||||||
|
struct uniphier_pinctrl_socdata *socdata; |
||||||
|
}; |
||||||
|
|
||||||
|
extern const struct pinctrl_ops uniphier_pinctrl_ops; |
||||||
|
|
||||||
|
int uniphier_pinctrl_probe(struct udevice *dev, |
||||||
|
struct uniphier_pinctrl_socdata *socdata); |
||||||
|
|
||||||
|
int uniphier_pinctrl_remove(struct udevice *dev); |
||||||
|
|
||||||
|
#endif /* __PINCTRL_UNIPHIER_H__ */ |
Loading…
Reference in new issue