pinctrl: uniphier: add UniPhier pinctrl core support
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>
This commit is contained in:
parent
8a5f6129d1
commit
5dc626f836
@ -124,4 +124,6 @@ config PINCTRL_SANDBOX
|
||||
|
||||
endif
|
||||
|
||||
source "drivers/pinctrl/uniphier/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
@ -3,3 +3,5 @@ obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o
|
||||
|
||||
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
||||
obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
|
||||
|
||||
obj-$(CONFIG_ARCH_UNIPHIER) += uniphier/
|
||||
|
6
drivers/pinctrl/uniphier/Kconfig
Normal file
6
drivers/pinctrl/uniphier/Kconfig
Normal file
@ -0,0 +1,6 @@
|
||||
if ARCH_UNIPHIER
|
||||
|
||||
config PINCTRL_UNIPHIER_CORE
|
||||
bool
|
||||
|
||||
endif
|
1
drivers/pinctrl/uniphier/Makefile
Normal file
1
drivers/pinctrl/uniphier/Makefile
Normal file
@ -0,0 +1 @@
|
||||
obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o
|
154
drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
Normal file
154
drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
Normal file
@ -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;
|
||||
}
|
113
drivers/pinctrl/uniphier/pinctrl-uniphier.h
Normal file
113
drivers/pinctrl/uniphier/pinctrl-uniphier.h
Normal file
@ -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
Block a user