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