mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-25 04:23:46 +00:00
addf358bac
Currently when using OF_PLATDATA the binding between devices and drivers is done trying to match the compatible string in the node with a driver name. However, usually a single driver supports multiple compatible strings which causes that only devices which its compatible string matches a driver name get bound. To overcome this issue, this patch adds the U_BOOT_DRIVER_ALIAS macro, which generates no code at all, but allows an easy way to declare driver name aliases. Thanks to this, dtoc could be improve to look for the driver name based on its alias when it populates the U_BOOT_DEVICE entry. Signed-off-by: Walter Lozano <walter.lozano@collabora.com> Reviewed-by: Simon Glass <sjg@chromium.org>
195 lines
4.2 KiB
C
195 lines
4.2 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2019 DENX Software Engineering
|
|
* Lukasz Majewski, DENX Software Engineering, lukma@denx.de
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <log.h>
|
|
#include <dm/device_compat.h>
|
|
#include <dm/devres.h>
|
|
#include <linux/io.h>
|
|
#include <linux/err.h>
|
|
#include <dm.h>
|
|
#include <dm/pinctrl.h>
|
|
#include <dm/read.h>
|
|
#include "pinctrl-mxs.h"
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
struct mxs_pinctrl_priv {
|
|
void __iomem *base;
|
|
const struct mxs_regs *regs;
|
|
};
|
|
|
|
static unsigned long mxs_dt_node_to_map(struct udevice *conf)
|
|
{
|
|
unsigned long config = 0;
|
|
int ret;
|
|
u32 val;
|
|
|
|
ret = dev_read_u32(conf, "fsl,drive-strength", &val);
|
|
if (!ret)
|
|
config = val | MA_PRESENT;
|
|
|
|
ret = dev_read_u32(conf, "fsl,voltage", &val);
|
|
if (!ret)
|
|
config |= val << VOL_SHIFT | VOL_PRESENT;
|
|
|
|
ret = dev_read_u32(conf, "fsl,pull-up", &val);
|
|
if (!ret)
|
|
config |= val << PULL_SHIFT | PULL_PRESENT;
|
|
|
|
return config;
|
|
}
|
|
|
|
static int mxs_pinctrl_set_mux(struct udevice *dev, u32 val, int bank, int pin)
|
|
{
|
|
struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
|
|
int muxsel = MUXID_TO_MUXSEL(val), shift;
|
|
void __iomem *reg;
|
|
|
|
reg = iomux->base + iomux->regs->muxsel;
|
|
reg += bank * 0x20 + pin / 16 * 0x10;
|
|
shift = pin % 16 * 2;
|
|
|
|
mxs_pinctrl_rmwl(muxsel, 0x3, shift, reg);
|
|
debug(" mux %d,", muxsel);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mxs_pinctrl_set_state(struct udevice *dev, struct udevice *conf)
|
|
{
|
|
struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
|
|
u32 *pin_data, val, ma, vol, pull;
|
|
int npins, size, i, ret;
|
|
unsigned long config;
|
|
|
|
debug("\n%s: set state: %s\n", __func__, conf->name);
|
|
|
|
size = dev_read_size(conf, "fsl,pinmux-ids");
|
|
if (size < 0)
|
|
return size;
|
|
|
|
if (!size || size % sizeof(int)) {
|
|
dev_err(dev, "Invalid fsl,pinmux-ids property in %s\n",
|
|
conf->name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
npins = size / sizeof(int);
|
|
|
|
pin_data = devm_kzalloc(dev, size, 0);
|
|
if (!pin_data)
|
|
return -ENOMEM;
|
|
|
|
ret = dev_read_u32_array(conf, "fsl,pinmux-ids", pin_data, npins);
|
|
if (ret) {
|
|
dev_err(dev, "Error reading pin data.\n");
|
|
devm_kfree(dev, pin_data);
|
|
return -EINVAL;
|
|
}
|
|
|
|
config = mxs_dt_node_to_map(conf);
|
|
|
|
ma = CONFIG_TO_MA(config);
|
|
vol = CONFIG_TO_VOL(config);
|
|
pull = CONFIG_TO_PULL(config);
|
|
|
|
for (i = 0; i < npins; i++) {
|
|
int pinid, bank, pin, shift;
|
|
void __iomem *reg;
|
|
|
|
val = pin_data[i];
|
|
|
|
pinid = MUXID_TO_PINID(val);
|
|
bank = PINID_TO_BANK(pinid);
|
|
pin = PINID_TO_PIN(pinid);
|
|
|
|
debug("(val: 0x%x) pin %d,", val, pinid);
|
|
/* Setup pinmux */
|
|
mxs_pinctrl_set_mux(dev, val, bank, pin);
|
|
|
|
debug(" ma: %d, vol: %d, pull: %d\n", ma, vol, pull);
|
|
|
|
/* drive */
|
|
reg = iomux->base + iomux->regs->drive;
|
|
reg += bank * 0x40 + pin / 8 * 0x10;
|
|
|
|
/* mA */
|
|
if (config & MA_PRESENT) {
|
|
shift = pin % 8 * 4;
|
|
mxs_pinctrl_rmwl(ma, 0x3, shift, reg);
|
|
}
|
|
|
|
/* vol */
|
|
if (config & VOL_PRESENT) {
|
|
shift = pin % 8 * 4 + 2;
|
|
if (vol)
|
|
writel(1 << shift, reg + SET);
|
|
else
|
|
writel(1 << shift, reg + CLR);
|
|
}
|
|
|
|
/* pull */
|
|
if (config & PULL_PRESENT) {
|
|
reg = iomux->base + iomux->regs->pull;
|
|
reg += bank * 0x10;
|
|
shift = pin;
|
|
if (pull)
|
|
writel(1 << shift, reg + SET);
|
|
else
|
|
writel(1 << shift, reg + CLR);
|
|
}
|
|
}
|
|
|
|
devm_kfree(dev, pin_data);
|
|
return 0;
|
|
}
|
|
|
|
static struct pinctrl_ops mxs_pinctrl_ops = {
|
|
.set_state = mxs_pinctrl_set_state,
|
|
};
|
|
|
|
static int mxs_pinctrl_probe(struct udevice *dev)
|
|
{
|
|
struct mxs_pinctrl_priv *iomux = dev_get_priv(dev);
|
|
|
|
iomux->base = dev_read_addr_ptr(dev);
|
|
iomux->regs = (struct mxs_regs *)dev_get_driver_data(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct mxs_regs imx23_regs = {
|
|
.muxsel = 0x100,
|
|
.drive = 0x200,
|
|
.pull = 0x400,
|
|
};
|
|
|
|
static const struct mxs_regs imx28_regs = {
|
|
.muxsel = 0x100,
|
|
.drive = 0x300,
|
|
.pull = 0x600,
|
|
};
|
|
|
|
static const struct udevice_id mxs_pinctrl_match[] = {
|
|
{ .compatible = "fsl,imx23-pinctrl", .data = (ulong)&imx23_regs },
|
|
{ .compatible = "fsl,imx28-pinctrl", .data = (ulong)&imx28_regs },
|
|
{ /* sentinel */ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(fsl_imx23_pinctrl) = {
|
|
.name = "fsl_imx23_pinctrl",
|
|
.id = UCLASS_PINCTRL,
|
|
.of_match = of_match_ptr(mxs_pinctrl_match),
|
|
.probe = mxs_pinctrl_probe,
|
|
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
|
.bind = dm_scan_fdt_dev,
|
|
#endif
|
|
.priv_auto_alloc_size = sizeof(struct mxs_pinctrl_priv),
|
|
.ops = &mxs_pinctrl_ops,
|
|
};
|
|
|
|
U_BOOT_DRIVER_ALIAS(fsl_imx23_pinctrl, fsl_imx28_pinctrl)
|