Re: [PATCH 1/7] pinctrl: realtek: Add common pinctrl driver for Realtek DHC RTD SoCs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Wed, Jul 26, 2023 at 05:04:03PM +0800, TY Chang kirjoitti:
> The RTD SoCs share a similar design for pinmux and pinconfig.
> This common pinctrl driver supports different variants within the RTD
> SoCs.

> +config PINCTRL_RTD
> +	tristate "Realtek DHC core pin controller driver"

Why is it user-visible?

> +	depends on ARCH_REALTEK

> +	default y

Why?

> +	select PINMUX
> +	select GENERIC_PINCONF

...

> +#include <linux/bitops.h>
> +#include <linux/io.h>
> +#include <linux/module.h>

> +#include <linux/of.h>
> +#include <linux/of_address.h>

Not used or not needed, use proper platform driver APIs

> +#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>

Move this group outside generic headers...

> +#include <linux/platform_device.h>
> +#include <linux/seq_file.h>
> +#include <linux/slab.h>

+ Blank line. You have missing headers (like types.h)/

...here.

> +#include "../core.h"
> +#include "../pinctrl-utils.h"

+ Blank line.

> +#include "pinctrl-rtd.h"

...

> +static const struct pinconf_generic_params rtd_custom_bindings[] = {
> +	{"realtek,pdrive", RTD_P_DRIVE, 0},
> +	{"realtek,ndrive", RTD_N_DRIVE, 0},
> +	{"realtek,dcycle", RTD_D_CYCLE, 0},

Use C99 initializers.

> +};

...

> +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;

Actually it's boolean. Why int?

> +	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++;
> +	}

This can be a long list, why not simply print only mapped function?

> +	if (!is_map)
> +		seq_puts(s, "[not defined]");
> +}

...

> +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;

Can the error (?) case be handled first?

	if (data->info->muxes[pin].name)
		return NULL;

> +}

...

> +static void rtd_pinctrl_update_bits(struct rtd_pinctrl *data, unsigned int offset,
> +				    unsigned int mask, unsigned int val)
> +{
> +	unsigned int reg = readl_relaxed(data->base + offset);

> +	reg &= ~mask;
> +	reg |= (mask & val);

Please, use idiomatic one liner:

	reg = (reg & ~mask) | (val & mask);

> +	writel_relaxed(reg, data->base + offset);
> +}

...

> +static const struct pinctrl_pin_desc
> +	*rtd_pinctrl_get_pin_by_number(struct rtd_pinctrl *data, int number)

Weird indentation.

> +{
> +	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;

	if (...)
		return NULL;

> +}

...

> +	switch ((u32)param) {

Why casting?!

> +	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);

In all cases like this, why do you need the message to be printed?

> +			return -ENOTSUPP;
> +		}
> +		smt_off = config_desc->base_bit + config_desc->smt_offset;
> +		set_val = arg;
> +
> +		mask = BIT(smt_off);
> +		val = set_val ? BIT(smt_off) : 0;
> +		rtd_pinctrl_update_bits(data, config_desc->reg_offset, mask, val);
> +		break;

...

> +	case PIN_CONFIG_DRIVE_STRENGTH:
> +		curr_off = config_desc->base_bit + config_desc->curr_offset;
> +		strength = arg;

> +		val = 0;

How is this assignment being used?

> +		switch (config_desc->curr_type) {
> +		case PADDRI_4_8:
> +			if (strength == 4)

BIT() ?

> +				val = 0;
> +			else if (strength == 8)

Ditto.

> +				val = BIT(curr_off);
> +			else
> +				return -EINVAL;
> +			break;
> +		case PADDRI_2_4:
> +			if (strength == 2)

Ditto.

> +				val = 0;
> +			else if (strength == 4)

Ditto.

> +				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);
> +		rtd_pinctrl_update_bits(data, config_desc->reg_offset, mask, val);
> +		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;
> +		}

Less error prone is to use division and multiplication. Something like

		pow_bit = config_desc->base_bit + config_desc->power_offset;
		reg_off = config_desc->reg_offset + 4 * (pow_bit / 32);
		pow_off = pow_bit % 32;

> +		set_val = arg;
> +		mask = BIT(pow_off);
> +		val = set_val ? mask : 0;
> +		rtd_pinctrl_update_bits(data, reg_off, mask, val);
> +		break;
> +
> +	case RTD_P_DRIVE:
> +		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;
> +		}

Ditto.

> +		mask = GENMASK(p_off + sconfig_desc->pdrive_maskbits - 1, p_off);

No, this is suboptimal, better

		mask = GENMASK(sconfig_desc->pdrive_maskbits - 1, 0) << p_off;

> +		val = set_val << p_off;
> +		rtd_pinctrl_update_bits(data, reg_off, mask, val);
> +		break;
> +
> +	case RTD_N_DRIVE:
> +		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;
> +		}

As per above.

> +		mask = GENMASK(n_off + sconfig_desc->ndrive_maskbits - 1, n_off);

As per above.

> +		val = set_val << n_off;
> +		rtd_pinctrl_update_bits(data, reg_off, mask, val);
> +		break;

> +	case RTD_D_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;
> +		mask = GENMASK(sconfig_desc->dcycle_offset +
> +		sconfig_desc->dcycle_maskbits - 1, sconfig_desc->dcycle_offset);

Broken indentation and see above.

> +		val = set_val << sconfig_desc->dcycle_offset;
> +		rtd_pinctrl_update_bits(data, sconfig_desc->reg_offset, mask, val);
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}

...

> +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;

How is this assignment being used?

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

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

This is a dead code, why?!

> +}

...

> +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;

How is this assignment being used?

> +	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;
> +}

...

> +int rtd_pinctrl_probe(struct platform_device *pdev, const struct rtd_pinctrl_desc *desc)
> +{
> +	struct rtd_pinctrl *data;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->base = of_iomap(pdev->dev.of_node, 0);

Use proper platform driver API.
Also, why not devm_*()?

> +	if (IS_ERR(data->base))
> +		return PTR_ERR(data->base);
> +
> +	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->pcdev = pinctrl_register(&data->desc, &pdev->dev, data);

Why not devm_*()?

> +	if (!data->pcdev)
> +		return -ENOMEM;

> +	platform_set_drvdata(pdev, data);

Is this used anyhow?

> +	dev_dbg(&pdev->dev, "probed\n");
> +
> +	return 0;
> +}

...

> +EXPORT_SYMBOL(rtd_pinctrl_probe);

Use namespace.

...

> +/*
> + * Copyright (c) 2023 Realtek Semiconductor Corp.
> + */

One line.

...

No ifdeffery guard?

...

> +#define NA 0xffffffff

What is this? Bit mask? U32_MAX? -1? 

> +#define PADDRI_4_8 1
> +#define PADDRI_2_4 0

...

> +struct rtd_pin_group_desc {
> +	const char *name;
> +	const unsigned int *pins;
> +	unsigned int num_pins;
> +};
> +
> +struct rtd_pin_func_desc {
> +	const char *name;
> +	const char * const *groups;
> +	unsigned int num_groups;
> +};

NIH struct pingroup, struct pinfunction.

-- 
With Best Regards,
Andy Shevchenko





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux