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