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