uboot/drivers/pinctrl/exynos/pinctrl-exynos.c
<<
>>
Prefs
   1/*
   2 * Exynos pinctrl driver common code.
   3 * Copyright (C) 2016 Samsung Electronics
   4 * Thomas Abraham <thomas.ab@samsung.com>
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <common.h>
  10#include <dm.h>
  11#include <errno.h>
  12#include <asm/io.h>
  13#include "pinctrl-exynos.h"
  14
  15DECLARE_GLOBAL_DATA_PTR;
  16
  17/**
  18 * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral.
  19 * conf: soc specific pin configuration data array
  20 * num_conf: number of configurations in the conf array.
  21 * base: base address of the pin controller.
  22 */
  23void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf,
  24                unsigned int num_conf, unsigned long base)
  25{
  26        unsigned int idx, val;
  27
  28        for (idx = 0; idx < num_conf; idx++) {
  29                val = readl(base + conf[idx].offset);
  30                val &= ~(conf[idx].mask);
  31                val |= conf[idx].value;
  32                writel(val, base + conf[idx].offset);
  33        }
  34}
  35
  36/* given a pin-name, return the address of pin config registers */
  37static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name,
  38                                                u32 *pin)
  39{
  40        struct exynos_pinctrl_priv *priv = dev_get_priv(dev);
  41        const struct samsung_pin_ctrl *pin_ctrl = priv->pin_ctrl;
  42        const struct samsung_pin_bank_data *bank_data = pin_ctrl->pin_banks;
  43        u32 nr_banks = pin_ctrl->nr_banks, idx = 0;
  44        char bank[10];
  45
  46        /*
  47         * The format of the pin name is <bank name>-<pin_number>.
  48         * Example: gpa0-4 (gpa0 is the bank name and 4 is the pin number.
  49         */
  50        while (pin_name[idx] != '-') {
  51                bank[idx] = pin_name[idx];
  52                idx++;
  53        }
  54        bank[idx] = '\0';
  55        *pin = pin_name[++idx] - '0';
  56
  57        /* lookup the pin bank data using the pin bank name */
  58        for (idx = 0; idx < nr_banks; idx++)
  59                if (!strcmp(bank, bank_data[idx].name))
  60                        break;
  61
  62        return priv->base + bank_data[idx].offset;
  63}
  64
  65/**
  66 * exynos_pinctrl_set_state: configure a pin state.
  67 * dev: the pinctrl device to be configured.
  68 * config: the state to be configured.
  69 */
  70int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config)
  71{
  72        const void *fdt = gd->fdt_blob;
  73        int node = dev_of_offset(config);
  74        unsigned int count, idx, pin_num;
  75        unsigned int pinfunc, pinpud, pindrv;
  76        unsigned long reg, value;
  77        const char *name;
  78
  79        /*
  80         * refer to the following document for the pinctrl bindings
  81         * linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
  82         */
  83        count = fdt_stringlist_count(fdt, node, "samsung,pins");
  84        if (count <= 0)
  85                return -EINVAL;
  86
  87        pinfunc = fdtdec_get_int(fdt, node, "samsung,pin-function", -1);
  88        pinpud = fdtdec_get_int(fdt, node, "samsung,pin-pud", -1);
  89        pindrv = fdtdec_get_int(fdt, node, "samsung,pin-drv", -1);
  90
  91        for (idx = 0; idx < count; idx++) {
  92                name = fdt_stringlist_get(fdt, node, "samsung,pins", idx, NULL);
  93                if (!name)
  94                        continue;
  95                reg = pin_to_bank_base(dev, name, &pin_num);
  96
  97                if (pinfunc != -1) {
  98                        value = readl(reg + PIN_CON);
  99                        value &= ~(0xf << (pin_num << 2));
 100                        value |= (pinfunc << (pin_num << 2));
 101                        writel(value, reg + PIN_CON);
 102                }
 103
 104                if (pinpud != -1) {
 105                        value = readl(reg + PIN_PUD);
 106                        value &= ~(0x3 << (pin_num << 1));
 107                        value |= (pinpud << (pin_num << 1));
 108                        writel(value, reg + PIN_PUD);
 109                }
 110
 111                if (pindrv != -1) {
 112                        value = readl(reg + PIN_DRV);
 113                        value &= ~(0x3 << (pin_num << 1));
 114                        value |= (pindrv << (pin_num << 1));
 115                        writel(value, reg + PIN_DRV);
 116                }
 117        }
 118
 119        return 0;
 120}
 121
 122int exynos_pinctrl_probe(struct udevice *dev)
 123{
 124        struct exynos_pinctrl_priv *priv;
 125        fdt_addr_t base;
 126
 127        priv = dev_get_priv(dev);
 128        if (!priv)
 129                return -EINVAL;
 130
 131        base = dev_get_addr(dev);
 132        if (base == FDT_ADDR_T_NONE)
 133                return -EINVAL;
 134
 135        priv->base = base;
 136        priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) +
 137                                dev->req_seq;
 138
 139        return 0;
 140}
 141