drivers/pinctrl/visconti/pinctrl-common.c

Source file repositories/reference/linux-study-clean/drivers/pinctrl/visconti/pinctrl-common.c

File Facts

System
Linux kernel
Corpus path
drivers/pinctrl/visconti/pinctrl-common.c
Extension
.c
Size
8868 bytes
Lines
329
Domain
Driver Families
Bucket
drivers/pinctrl
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct visconti_pinctrl {
	void __iomem *base;
	struct device *dev;
	struct pinctrl_dev *pctl;
	struct pinctrl_desc pctl_desc;

	const struct visconti_pinctrl_devdata  *devdata;

	spinlock_t lock; /* protect pinctrl register */
};

/* pinconf */
static int visconti_pin_config_set(struct pinctrl_dev *pctldev,
				  unsigned int _pin,
				  unsigned long *configs,
				  unsigned int num_configs)
{
	struct visconti_pinctrl *priv = pinctrl_dev_get_drvdata(pctldev);
	const struct visconti_desc_pin *pin = &priv->devdata->pins[_pin];
	enum pin_config_param param;
	unsigned int arg;
	int i, ret = 0;
	unsigned int val, set_val, pude_val;
	unsigned long flags;

	dev_dbg(priv->dev, "%s: pin = %d (%s)\n", __func__, _pin, pin->pin.name);

	spin_lock_irqsave(&priv->lock, flags);

	for (i = 0; i < num_configs; i++) {
		set_val = 0;
		pude_val = 0;

		param = pinconf_to_config_param(configs[i]);
		switch (param) {
		case PIN_CONFIG_BIAS_PULL_UP:
			set_val = 1;
			fallthrough;
		case PIN_CONFIG_BIAS_PULL_DOWN:
			/* update pudsel setting */
			val = readl(priv->base + pin->pudsel_offset);
			val &= ~BIT(pin->pud_shift);
			val |= set_val << pin->pud_shift;
			writel(val, priv->base + pin->pudsel_offset);
			pude_val = 1;
			fallthrough;
		case PIN_CONFIG_BIAS_DISABLE:
			/* update pude setting */
			val = readl(priv->base + pin->pude_offset);
			val &= ~BIT(pin->pud_shift);
			val |= pude_val << pin->pud_shift;
			writel(val, priv->base + pin->pude_offset);
			dev_dbg(priv->dev, "BIAS(%d): off = 0x%x val = 0x%x\n",
				param, pin->pude_offset, val);
			break;

		case PIN_CONFIG_DRIVE_STRENGTH:
			arg = pinconf_to_config_argument(configs[i]);
			dev_dbg(priv->dev, "DRV_STR arg = %d\n", arg);
			switch (arg) {
			case 2:
			case 4:
			case 8:
			case 16:
			case 24:
			case 32:
				/*
				 * I/O drive capacity setting:
				 * 2mA: 0
				 * 4mA: 1
				 * 8mA: 3
				 * 16mA: 7
				 * 24mA: 11
				 * 32mA: 15
				 */
				set_val = DIV_ROUND_CLOSEST(arg, 2) - 1;
				break;
			default:
				ret = -EINVAL;
				goto err;
			}
			/* update drive setting */
			val = readl(priv->base + pin->dsel_offset);
			val &= ~(DSEL_MASK << pin->dsel_shift);
			val |= set_val << pin->dsel_shift;
			writel(val, priv->base + pin->dsel_offset);
			break;

		default:
			ret = -EOPNOTSUPP;

Annotation

Implementation Notes