Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/arch/arm/boot/dts/allwinner/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 2 kB image not shown  

SSL pinctrl-rtd.c   Sprache: unbekannt

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Realtek DHC pin controller driver
 *
 * Copyright (c) 2023 Realtek Semiconductor Corp.
 */


#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include "../core.h"
#include "../pinctrl-utils.h"
#include "pinctrl-rtd.h"

struct rtd_pinctrl {
 struct device *dev;
 struct pinctrl_dev *pcdev;
 void __iomem *base;
 struct pinctrl_desc desc;
 const struct rtd_pinctrl_desc *info;
 struct regmap *regmap_pinctrl;
};

/* custom pinconf parameters */
#define RTD_DRIVE_STRENGH_P (PIN_CONFIG_END + 1)
#define RTD_DRIVE_STRENGH_N (PIN_CONFIG_END + 2)
#define RTD_DUTY_CYCLE (PIN_CONFIG_END + 3)

static const struct pinconf_generic_params rtd_custom_bindings[] = {
 {"realtek,drive-strength-p", RTD_DRIVE_STRENGH_P, 0},
 {"realtek,drive-strength-n", RTD_DRIVE_STRENGH_N, 0},
 {"realtek,duty-cycle", RTD_DUTY_CYCLE, 0},
};

static int rtd_pinctrl_get_groups_count(struct pinctrl_dev *pcdev)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);

 return data->info->num_groups;
}

static const char *rtd_pinctrl_get_group_name(struct pinctrl_dev *pcdev,
           unsigned int selector)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);

 return data->info->groups[selector].name;
}

static int rtd_pinctrl_get_group_pins(struct pinctrl_dev *pcdev,
          unsigned int selector,
          const unsigned int **pins,
          unsigned int *num_pins)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);

 *pins = data->info->groups[selector].pins;
 *num_pins = data->info->groups[selector].num_pins;

 return 0;
}

static void rtd_pinctrl_dbg_show(struct pinctrl_dev *pcdev,
     struct seq_file *s,
     unsigned int offset)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
 const struct rtd_pin_desc *mux = &data->info->muxes[offset];
 const struct rtd_pin_mux_desc *func;
 u32 val;
 u32 mask;
 u32 pin_val;
 int is_map;

 if (!mux->name) {
  seq_puts(s, "[not defined]");
  return;
 }
 val = readl_relaxed(data->base + mux->mux_offset);
 mask = mux->mux_mask;
 pin_val = val & mask;

 is_map = 0;
 func = &mux->functions[0];
 seq_puts(s, "function: ");
 while (func->name) {
  if (func->mux_value == pin_val) {
   is_map = 1;
   seq_printf(s, "[%s] ", func->name);
  } else {
   seq_printf(s, "%s ", func->name);
  }
  func++;
 }
 if (!is_map)
  seq_puts(s, "[not defined]");
}

static const struct pinctrl_ops rtd_pinctrl_ops = {
 .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
 .dt_free_map = pinctrl_utils_free_map,
 .get_groups_count = rtd_pinctrl_get_groups_count,
 .get_group_name = rtd_pinctrl_get_group_name,
 .get_group_pins = rtd_pinctrl_get_group_pins,
 .pin_dbg_show = rtd_pinctrl_dbg_show,
};

static int rtd_pinctrl_get_functions_count(struct pinctrl_dev *pcdev)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);

 return data->info->num_functions;
}

static const char *rtd_pinctrl_get_function_name(struct pinctrl_dev *pcdev,
       unsigned int selector)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);

 return data->info->functions[selector].name;
}

static int rtd_pinctrl_get_function_groups(struct pinctrl_dev *pcdev,
        unsigned int selector,
        const char * const **groups,
        unsigned int * const num_groups)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);

 *groups = data->info->functions[selector].groups;
 *num_groups = data->info->functions[selector].num_groups;

 return 0;
}

static const struct rtd_pin_desc *rtd_pinctrl_find_mux(struct rtd_pinctrl *data, unsigned int pin)
{
 if (data->info->muxes[pin].name)
  return &data->info->muxes[pin];

 return NULL;
}

static int rtd_pinctrl_set_one_mux(struct pinctrl_dev *pcdev,
       unsigned int pin, const char *func_name)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
 const struct rtd_pin_desc *mux;
 int ret = 0;
 int i;

 mux = rtd_pinctrl_find_mux(data, pin);
 if (!mux)
  return 0;

 if (!mux->functions) {
  if (!mux->name)
   dev_err(pcdev->dev, "NULL pin has no functions\n");
  else
   dev_err(pcdev->dev, "No functions available for pin %s\n", mux->name);
  return -ENOTSUPP;
 }

 for (i = 0; mux->functions[i].name; i++) {
  if (strcmp(mux->functions[i].name, func_name) != 0)
   continue;
  ret = regmap_update_bits(data->regmap_pinctrl, mux->mux_offset, mux->mux_mask,
     mux->functions[i].mux_value);
  return ret;
 }

 if (!mux->name) {
  dev_err(pcdev->dev, "NULL pin provided for function %s\n", func_name);
  return -EINVAL;
 }

 dev_err(pcdev->dev, "No function %s available for pin %s\n", func_name, mux->name);

 return -EINVAL;
}

static int rtd_pinctrl_set_mux(struct pinctrl_dev *pcdev,
          unsigned int function, unsigned int group)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
 const unsigned int *pins;
 unsigned int num_pins;
 const char *func_name;
 const char *group_name;
 int i, ret;

 func_name = data->info->functions[function].name;
 group_name = data->info->groups[group].name;

 ret = rtd_pinctrl_get_group_pins(pcdev, group, &pins, &num_pins);
 if (ret) {
  dev_err(pcdev->dev, "Getting pins for group %s failed\n", group_name);
  return ret;
 }

 for (i = 0; i < num_pins; i++) {
  ret = rtd_pinctrl_set_one_mux(pcdev, pins[i], func_name);
  if (ret)
   return ret;
 }

 return 0;
}

static int rtd_pinctrl_gpio_request_enable(struct pinctrl_dev *pcdev,
        struct pinctrl_gpio_range *range,
        unsigned int offset)
{
 return rtd_pinctrl_set_one_mux(pcdev, offset, "gpio");
}

static const struct pinmux_ops rtd_pinmux_ops = {
 .get_functions_count = rtd_pinctrl_get_functions_count,
 .get_function_name = rtd_pinctrl_get_function_name,
 .get_function_groups = rtd_pinctrl_get_function_groups,
 .set_mux = rtd_pinctrl_set_mux,
 .gpio_request_enable = rtd_pinctrl_gpio_request_enable,
};

static const struct pinctrl_pin_desc
 *rtd_pinctrl_get_pin_by_number(struct rtd_pinctrl *data, int number)
{
 int i;

 for (i = 0; i < data->info->num_pins; i++) {
  if (data->info->pins[i].number == number)
   return &data->info->pins[i];
 }

 return NULL;
}

static const struct rtd_pin_config_desc
 *rtd_pinctrl_find_config(struct rtd_pinctrl *data, unsigned int pin)
{
 if (data->info->configs[pin].name)
  return &data->info->configs[pin];

 return NULL;
}

static const struct rtd_pin_sconfig_desc *rtd_pinctrl_find_sconfig(struct rtd_pinctrl *data,
           unsigned int pin)
{
 int i;
 const struct pinctrl_pin_desc *pin_desc;
 const char *pin_name;

 pin_desc = rtd_pinctrl_get_pin_by_number(data, pin);
 if (!pin_desc)
  return NULL;

 pin_name = pin_desc->name;

 for (i = 0; i < data->info->num_sconfigs; i++) {
  if (strcmp(data->info->sconfigs[i].name, pin_name) == 0)
   return &data->info->sconfigs[i];
 }

 return NULL;
}

static int rtd_pconf_parse_conf(struct rtd_pinctrl *data,
    unsigned int pinnr,
    enum pin_config_param param,
    enum pin_config_param arg)
{
 const struct rtd_pin_config_desc *config_desc;
 const struct rtd_pin_sconfig_desc *sconfig_desc;
 u8 set_val = 0;
 u16 strength;
 u32 val;
 u32 mask;
 u32 pulsel_off, pulen_off, smt_off, curr_off, pow_off, reg_off, p_off, n_off;
 const char *name = data->info->pins[pinnr].name;
 int ret = 0;

 config_desc = rtd_pinctrl_find_config(data, pinnr);
 if (!config_desc) {
  dev_err(data->dev, "Not support pin config for pin: %s\n", name);
  return -ENOTSUPP;
 }
 switch ((u32)param) {
 case PIN_CONFIG_INPUT_SCHMITT:
 case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
  if (config_desc->smt_offset == NA) {
   dev_err(data->dev, "Not support input schmitt for pin: %s\n", name);
   return -ENOTSUPP;
  }
  smt_off = config_desc->base_bit + config_desc->smt_offset;
  reg_off = config_desc->reg_offset;
  set_val = arg;

  mask = BIT(smt_off);
  val = set_val ? BIT(smt_off) : 0;
  break;

 case PIN_CONFIG_DRIVE_PUSH_PULL:
  if (config_desc->pud_en_offset == NA) {
   dev_err(data->dev, "Not support push pull for pin: %s\n", name);
   return -ENOTSUPP;
  }
  pulen_off = config_desc->base_bit + config_desc->pud_en_offset;
  reg_off = config_desc->reg_offset;

  mask =  BIT(pulen_off);
  val = 0;
  break;

 case PIN_CONFIG_BIAS_DISABLE:
  if (config_desc->pud_en_offset == NA) {
   dev_err(data->dev, "Not support bias disable for pin: %s\n", name);
   return -ENOTSUPP;
  }
  pulen_off = config_desc->base_bit + config_desc->pud_en_offset;
  reg_off = config_desc->reg_offset;

  mask =  BIT(pulen_off);
  val = 0;
  break;

 case PIN_CONFIG_BIAS_PULL_UP:
  if (config_desc->pud_en_offset == NA) {
   dev_err(data->dev, "Not support bias pull up for pin:%s\n", name);
   return -ENOTSUPP;
  }
  pulen_off = config_desc->base_bit + config_desc->pud_en_offset;
  pulsel_off = config_desc->base_bit + config_desc->pud_sel_offset;
  reg_off = config_desc->reg_offset;

  mask = BIT(pulen_off) | BIT(pulsel_off);
  val = mask;
  break;

 case PIN_CONFIG_BIAS_PULL_DOWN:
  if (config_desc->pud_en_offset == NA) {
   dev_err(data->dev, "Not support bias pull down for pin: %s\n", name);
   return -ENOTSUPP;
  }
  pulen_off = config_desc->base_bit + config_desc->pud_en_offset;
  pulsel_off = config_desc->base_bit + config_desc->pud_sel_offset;
  reg_off = config_desc->reg_offset;

  mask = BIT(pulen_off) | BIT(pulsel_off);
  val = BIT(pulen_off);
  break;

 case PIN_CONFIG_DRIVE_STRENGTH:
  curr_off = config_desc->base_bit + config_desc->curr_offset;
  reg_off = config_desc->reg_offset;
  strength = arg;
  val = 0;
  switch (config_desc->curr_type) {
  case PADDRI_4_8:
   if (strength == 4)
    val = 0;
   else if (strength == 8)
    val = BIT(curr_off);
   else
    return -EINVAL;
   break;
  case PADDRI_2_4:
   if (strength == 2)
    val = 0;
   else if (strength == 4)
    val = BIT(curr_off);
   else
    return -EINVAL;
   break;
  case NA:
   dev_err(data->dev, "Not support drive strength for pin: %s\n", name);
   return -ENOTSUPP;
  default:
   return -EINVAL;
  }
  mask = BIT(curr_off);
  break;

 case PIN_CONFIG_POWER_SOURCE:
  if (config_desc->power_offset == NA) {
   dev_err(data->dev, "Not support power source for pin: %s\n", name);
   return -ENOTSUPP;
  }
  reg_off = config_desc->reg_offset;
  pow_off = config_desc->base_bit + config_desc->power_offset;
  if (pow_off >= 32) {
   reg_off += 0x4;
   pow_off -= 32;
  }
  set_val = arg;
  mask = BIT(pow_off);
  val = set_val ? mask : 0;
  break;

 case RTD_DRIVE_STRENGH_P:
  sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr);
  if (!sconfig_desc) {
   dev_err(data->dev, "Not support P driving for pin: %s\n", name);
   return -ENOTSUPP;
  }
  set_val = arg;
  reg_off = sconfig_desc->reg_offset;
  p_off = sconfig_desc->pdrive_offset;
  if (p_off >= 32) {
   reg_off += 0x4;
   p_off -= 32;
  }
  mask = GENMASK(p_off + sconfig_desc->pdrive_maskbits - 1, p_off);
  val = set_val << p_off;
  break;

 case RTD_DRIVE_STRENGH_N:
  sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr);
  if (!sconfig_desc) {
   dev_err(data->dev, "Not support N driving for pin: %s\n", name);
   return -ENOTSUPP;
  }
  set_val = arg;
  reg_off = sconfig_desc->reg_offset;
  n_off = sconfig_desc->ndrive_offset;
  if (n_off >= 32) {
   reg_off += 0x4;
   n_off -= 32;
  }
  mask = GENMASK(n_off + sconfig_desc->ndrive_maskbits - 1, n_off);
  val = set_val << n_off;
  break;

 case RTD_DUTY_CYCLE:
  sconfig_desc = rtd_pinctrl_find_sconfig(data, pinnr);
  if (!sconfig_desc || sconfig_desc->dcycle_offset == NA) {
   dev_err(data->dev, "Not support duty cycle for pin: %s\n", name);
   return -ENOTSUPP;
  }
  set_val = arg;
  reg_off = config_desc->reg_offset;
  mask = GENMASK(sconfig_desc->dcycle_offset +
  sconfig_desc->dcycle_maskbits - 1, sconfig_desc->dcycle_offset);
  val = set_val << sconfig_desc->dcycle_offset;
  break;

 default:
  dev_err(data->dev, "unsupported pinconf: %d\n", (u32)param);
  return -EINVAL;
 }

 ret = regmap_update_bits(data->regmap_pinctrl, reg_off, mask, val);
 if (ret)
  dev_err(data->dev, "could not update pinconf(%d) for pin(%s)\n", (u32)param, name);

 return ret;
}

static int rtd_pin_config_get(struct pinctrl_dev *pcdev, unsigned int pinnr,
         unsigned long *config)
{
 unsigned int param = pinconf_to_config_param(*config);
 unsigned int arg = 0;

 switch (param) {
 default:
  return -ENOTSUPP;
 }

 *config = pinconf_to_config_packed(param, arg);
 return 0;
}

static int rtd_pin_config_set(struct pinctrl_dev *pcdev, unsigned int pinnr,
         unsigned long *configs, unsigned int num_configs)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
 int i;
 int ret = 0;

 for (i = 0; i < num_configs; i++) {
  ret = rtd_pconf_parse_conf(data, pinnr,
        pinconf_to_config_param(configs[i]),
        pinconf_to_config_argument(configs[i]));
  if (ret < 0)
   return ret;
 }

 return 0;
}

static int rtd_pin_config_group_set(struct pinctrl_dev *pcdev, unsigned int group,
        unsigned long *configs, unsigned int num_configs)
{
 struct rtd_pinctrl *data = pinctrl_dev_get_drvdata(pcdev);
 const unsigned int *pins;
 unsigned int num_pins;
 const char *group_name;
 int i, ret;

 group_name = data->info->groups[group].name;

 ret = rtd_pinctrl_get_group_pins(pcdev, group, &pins, &num_pins);
 if (ret) {
  dev_err(pcdev->dev, "Getting pins for group %s failed\n", group_name);
  return ret;
 }

 for (i = 0; i < num_pins; i++) {
  ret = rtd_pin_config_set(pcdev, pins[i], configs, num_configs);
  if (ret)
   return ret;
 }

 return 0;
}

static const struct pinconf_ops rtd_pinconf_ops = {
 .is_generic = true,
 .pin_config_get = rtd_pin_config_get,
 .pin_config_set = rtd_pin_config_set,
 .pin_config_group_set = rtd_pin_config_group_set,
};

static const struct regmap_config rtd_pinctrl_regmap_config = {
 .reg_bits = 32,
 .val_bits = 32,
 .reg_stride = 4,
 .use_relaxed_mmio = true,
};

int rtd_pinctrl_probe(struct platform_device *pdev, const struct rtd_pinctrl_desc *desc)
{
 struct rtd_pinctrl *data;
 int ret;

 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 if (!data)
  return -ENOMEM;

 data->base = of_iomap(pdev->dev.of_node, 0);
 if (!data->base)
  return -ENOMEM;

 data->dev = &pdev->dev;
 data->info = desc;
 data->desc.name = dev_name(&pdev->dev);
 data->desc.pins = data->info->pins;
 data->desc.npins = data->info->num_pins;
 data->desc.pctlops = &rtd_pinctrl_ops;
 data->desc.pmxops = &rtd_pinmux_ops;
 data->desc.confops = &rtd_pinconf_ops;
 data->desc.custom_params = rtd_custom_bindings;
 data->desc.num_custom_params = ARRAY_SIZE(rtd_custom_bindings);
 data->desc.owner = THIS_MODULE;
 data->regmap_pinctrl = devm_regmap_init_mmio(data->dev, data->base,
           &rtd_pinctrl_regmap_config);

 if (IS_ERR(data->regmap_pinctrl)) {
  dev_err(data->dev, "failed to init regmap: %ld\n",
   PTR_ERR(data->regmap_pinctrl));
  ret = PTR_ERR(data->regmap_pinctrl);
  goto unmap;
 }

 data->pcdev = pinctrl_register(&data->desc, &pdev->dev, data);
 if (IS_ERR(data->pcdev)) {
  ret = PTR_ERR(data->pcdev);
  goto unmap;
 }

 platform_set_drvdata(pdev, data);

 dev_dbg(&pdev->dev, "probed\n");

 return 0;

unmap:
 iounmap(data->base);
 return ret;
}
EXPORT_SYMBOL(rtd_pinctrl_probe);

MODULE_DESCRIPTION("Realtek DHC SoC pinctrl driver");
MODULE_LICENSE("GPL v2");

Messung V0.5 in Prozent
C=97 H=94 G=95

[Verzeichnis aufwärts0.14unsichere VerbindungÜbersetzung europäischer Sprachen durch Browser2026-06-07]