brintos

brintos / linux-shallow public Read only

0
0
Text · 9.3 KiB · dca9636 Raw
382 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Core driver for the pin config portions of the pin control subsystem4 *5 * Copyright (C) 2011 ST-Ericsson SA6 * Written on behalf of Linaro for ST-Ericsson7 *8 * Author: Linus Walleij <linus.walleij@linaro.org>9 */10#define pr_fmt(fmt) "pinconfig core: " fmt11 12#include <linux/array_size.h>13#include <linux/debugfs.h>14#include <linux/device.h>15#include <linux/init.h>16#include <linux/module.h>17#include <linux/seq_file.h>18#include <linux/slab.h>19 20#include <linux/pinctrl/machine.h>21#include <linux/pinctrl/pinconf.h>22#include <linux/pinctrl/pinctrl.h>23 24#include "core.h"25#include "pinconf.h"26 27int pinconf_check_ops(struct pinctrl_dev *pctldev)28{29	const struct pinconf_ops *ops = pctldev->desc->confops;30 31	/* We have to be able to config the pins in SOME way */32	if (!ops->pin_config_set && !ops->pin_config_group_set) {33		dev_err(pctldev->dev,34			"pinconf has to be able to set a pins config\n");35		return -EINVAL;36	}37	return 0;38}39 40int pinconf_validate_map(const struct pinctrl_map *map, int i)41{42	if (!map->data.configs.group_or_pin) {43		pr_err("failed to register map %s (%d): no group/pin given\n",44		       map->name, i);45		return -EINVAL;46	}47 48	if (!map->data.configs.num_configs ||49			!map->data.configs.configs) {50		pr_err("failed to register map %s (%d): no configs given\n",51		       map->name, i);52		return -EINVAL;53	}54 55	return 0;56}57 58int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned int pin,59			   unsigned long *config)60{61	const struct pinconf_ops *ops = pctldev->desc->confops;62 63	if (!ops || !ops->pin_config_get) {64		dev_dbg(pctldev->dev,65			"cannot get pin configuration, .pin_config_get missing in driver\n");66		return -ENOTSUPP;67	}68 69	return ops->pin_config_get(pctldev, pin, config);70}71 72int pin_config_group_get(const char *dev_name, const char *pin_group,73			 unsigned long *config)74{75	struct pinctrl_dev *pctldev;76	const struct pinconf_ops *ops;77	int selector, ret;78 79	pctldev = get_pinctrl_dev_from_devname(dev_name);80	if (!pctldev) {81		ret = -EINVAL;82		return ret;83	}84 85	mutex_lock(&pctldev->mutex);86 87	ops = pctldev->desc->confops;88 89	if (!ops || !ops->pin_config_group_get) {90		dev_dbg(pctldev->dev,91			"cannot get configuration for pin group, missing group config get function in driver\n");92		ret = -ENOTSUPP;93		goto unlock;94	}95 96	selector = pinctrl_get_group_selector(pctldev, pin_group);97	if (selector < 0) {98		ret = selector;99		goto unlock;100	}101 102	ret = ops->pin_config_group_get(pctldev, selector, config);103 104unlock:105	mutex_unlock(&pctldev->mutex);106	return ret;107}108 109int pinconf_map_to_setting(const struct pinctrl_map *map,110			  struct pinctrl_setting *setting)111{112	struct pinctrl_dev *pctldev = setting->pctldev;113	int pin;114 115	switch (setting->type) {116	case PIN_MAP_TYPE_CONFIGS_PIN:117		pin = pin_get_from_name(pctldev,118					map->data.configs.group_or_pin);119		if (pin < 0) {120			dev_err(pctldev->dev, "could not map pin config for \"%s\"",121				map->data.configs.group_or_pin);122			return pin;123		}124		setting->data.configs.group_or_pin = pin;125		break;126	case PIN_MAP_TYPE_CONFIGS_GROUP:127		pin = pinctrl_get_group_selector(pctldev,128					 map->data.configs.group_or_pin);129		if (pin < 0) {130			dev_err(pctldev->dev, "could not map group config for \"%s\"",131				map->data.configs.group_or_pin);132			return pin;133		}134		setting->data.configs.group_or_pin = pin;135		break;136	default:137		return -EINVAL;138	}139 140	setting->data.configs.num_configs = map->data.configs.num_configs;141	setting->data.configs.configs = map->data.configs.configs;142 143	return 0;144}145 146void pinconf_free_setting(const struct pinctrl_setting *setting)147{148}149 150int pinconf_apply_setting(const struct pinctrl_setting *setting)151{152	struct pinctrl_dev *pctldev = setting->pctldev;153	const struct pinconf_ops *ops = pctldev->desc->confops;154	int ret;155 156	if (!ops) {157		dev_err(pctldev->dev, "missing confops\n");158		return -EINVAL;159	}160 161	switch (setting->type) {162	case PIN_MAP_TYPE_CONFIGS_PIN:163		if (!ops->pin_config_set) {164			dev_err(pctldev->dev, "missing pin_config_set op\n");165			return -EINVAL;166		}167		ret = ops->pin_config_set(pctldev,168				setting->data.configs.group_or_pin,169				setting->data.configs.configs,170				setting->data.configs.num_configs);171		if (ret < 0) {172			dev_err(pctldev->dev,173				"pin_config_set op failed for pin %d\n",174				setting->data.configs.group_or_pin);175			return ret;176		}177		break;178	case PIN_MAP_TYPE_CONFIGS_GROUP:179		if (!ops->pin_config_group_set) {180			dev_err(pctldev->dev,181				"missing pin_config_group_set op\n");182			return -EINVAL;183		}184		ret = ops->pin_config_group_set(pctldev,185				setting->data.configs.group_or_pin,186				setting->data.configs.configs,187				setting->data.configs.num_configs);188		if (ret < 0) {189			dev_err(pctldev->dev,190				"pin_config_group_set op failed for group %d\n",191				setting->data.configs.group_or_pin);192			return ret;193		}194		break;195	default:196		return -EINVAL;197	}198 199	return 0;200}201 202int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned int pin,203		       unsigned long *configs, size_t nconfigs)204{205	const struct pinconf_ops *ops;206 207	ops = pctldev->desc->confops;208	if (!ops || !ops->pin_config_set)209		return -ENOTSUPP;210 211	return ops->pin_config_set(pctldev, pin, configs, nconfigs);212}213 214#ifdef CONFIG_DEBUG_FS215 216static void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev,217				unsigned long *configs, unsigned int num_configs)218{219	const struct pinconf_ops *confops;220	int i;221 222	if (pctldev)223		confops = pctldev->desc->confops;224	else225		confops = NULL;226 227	for (i = 0; i < num_configs; i++) {228		seq_puts(s, "config ");229		if (confops && confops->pin_config_config_dbg_show)230			confops->pin_config_config_dbg_show(pctldev, s,231							    configs[i]);232		else233			seq_printf(s, "%08lx", configs[i]);234		seq_putc(s, '\n');235	}236}237 238void pinconf_show_map(struct seq_file *s, const struct pinctrl_map *map)239{240	struct pinctrl_dev *pctldev;241 242	pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);243 244	switch (map->type) {245	case PIN_MAP_TYPE_CONFIGS_PIN:246		seq_puts(s, "pin ");247		break;248	case PIN_MAP_TYPE_CONFIGS_GROUP:249		seq_puts(s, "group ");250		break;251	default:252		break;253	}254 255	seq_printf(s, "%s\n", map->data.configs.group_or_pin);256 257	pinconf_show_config(s, pctldev, map->data.configs.configs,258			    map->data.configs.num_configs);259}260 261void pinconf_show_setting(struct seq_file *s,262			  const struct pinctrl_setting *setting)263{264	struct pinctrl_dev *pctldev = setting->pctldev;265	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;266	struct pin_desc *desc;267 268	switch (setting->type) {269	case PIN_MAP_TYPE_CONFIGS_PIN:270		desc = pin_desc_get(setting->pctldev,271				    setting->data.configs.group_or_pin);272		seq_printf(s, "pin %s (%d)", desc->name,273			   setting->data.configs.group_or_pin);274		break;275	case PIN_MAP_TYPE_CONFIGS_GROUP:276		seq_printf(s, "group %s (%d)",277			   pctlops->get_group_name(pctldev,278					setting->data.configs.group_or_pin),279			   setting->data.configs.group_or_pin);280		break;281	default:282		break;283	}284 285	/*286	 * FIXME: We should really get the pin controller to dump the config287	 * values, so they can be decoded to something meaningful.288	 */289	pinconf_show_config(s, pctldev, setting->data.configs.configs,290			    setting->data.configs.num_configs);291}292 293static void pinconf_dump_pin(struct pinctrl_dev *pctldev,294			     struct seq_file *s, int pin)295{296	const struct pinconf_ops *ops = pctldev->desc->confops;297 298	/* no-op when not using generic pin config */299	pinconf_generic_dump_pins(pctldev, s, NULL, pin);300	if (ops && ops->pin_config_dbg_show)301		ops->pin_config_dbg_show(pctldev, s, pin);302}303 304static int pinconf_pins_show(struct seq_file *s, void *what)305{306	struct pinctrl_dev *pctldev = s->private;307	unsigned int i, pin;308 309	seq_puts(s, "Pin config settings per pin\n");310	seq_puts(s, "Format: pin (name): configs\n");311 312	mutex_lock(&pctldev->mutex);313 314	/* The pin number can be retrived from the pin controller descriptor */315	for (i = 0; i < pctldev->desc->npins; i++) {316		struct pin_desc *desc;317 318		pin = pctldev->desc->pins[i].number;319		desc = pin_desc_get(pctldev, pin);320		/* Skip if we cannot search the pin */321		if (!desc)322			continue;323 324		seq_printf(s, "pin %d (%s): ", pin, desc->name);325 326		pinconf_dump_pin(pctldev, s, pin);327		seq_putc(s, '\n');328	}329 330	mutex_unlock(&pctldev->mutex);331 332	return 0;333}334 335static void pinconf_dump_group(struct pinctrl_dev *pctldev,336			       struct seq_file *s, unsigned int selector,337			       const char *gname)338{339	const struct pinconf_ops *ops = pctldev->desc->confops;340 341	/* no-op when not using generic pin config */342	pinconf_generic_dump_pins(pctldev, s, gname, 0);343	if (ops && ops->pin_config_group_dbg_show)344		ops->pin_config_group_dbg_show(pctldev, s, selector);345}346 347static int pinconf_groups_show(struct seq_file *s, void *what)348{349	struct pinctrl_dev *pctldev = s->private;350	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;351	unsigned int ngroups = pctlops->get_groups_count(pctldev);352	unsigned int selector = 0;353 354	seq_puts(s, "Pin config settings per pin group\n");355	seq_puts(s, "Format: group (name): configs\n");356 357	while (selector < ngroups) {358		const char *gname = pctlops->get_group_name(pctldev, selector);359 360		seq_printf(s, "%u (%s): ", selector, gname);361		pinconf_dump_group(pctldev, s, selector, gname);362		seq_putc(s, '\n');363		selector++;364	}365 366	return 0;367}368 369DEFINE_SHOW_ATTRIBUTE(pinconf_pins);370DEFINE_SHOW_ATTRIBUTE(pinconf_groups);371 372void pinconf_init_device_debugfs(struct dentry *devroot,373			 struct pinctrl_dev *pctldev)374{375	debugfs_create_file("pinconf-pins", 0444,376			    devroot, pctldev, &pinconf_pins_fops);377	debugfs_create_file("pinconf-groups", 0444,378			    devroot, pctldev, &pinconf_groups_fops);379}380 381#endif382