/*
* 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>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#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>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "core.h"
#include "pinctrl-sunxi.h"
#include "pinctrl-sunxi-pins.h"
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) {
if (!strcmp(func->name, func_name))
return func;
func++;
}
}
}
return NULL;
}
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;
}
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;
}
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;
const char *function;
const char *group;
int ret, nmaps, i = 0;
u32 val;
*map = NULL;
*num_maps = 0;
ret = of_property_read_string(node, "allwinner,function", &function);
if (ret) {
dev_err(pctl->dev,
"missing allwinner,function property in node %s\n",
node->name);
return -EINVAL;
}
nmaps = of_property_count_strings(node, "allwinner,pins") * 2;
if (nmaps < 0) {
dev_err(pctl->dev,
"missing allwinner,pins property in node %s\n",