[PATCH 1/2] hwmon: ntc: Add DT support to NTC thermistor driver

Guenter Roeck linux at roeck-us.net
Mon Mar 11 23:21:44 EST 2013


On Mon, Mar 11, 2013 at 07:39:46AM +0530, Naveen Krishna Chatradhi wrote:
> This patch adds the DT support to NTC driver to parse the
> platform data.
> 
> Signed-off-by: Naveen Krishna Chatradhi <ch.naveen at samsung.com>
> ---
>  drivers/hwmon/ntc_thermistor.c |   93 ++++++++++++++++++++++++++++++++--------
>  1 file changed, 75 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
> index d92b237..cfedbd3 100644
> --- a/drivers/hwmon/ntc_thermistor.c
> +++ b/drivers/hwmon/ntc_thermistor.c
> @@ -26,6 +26,7 @@
>  #include <linux/math64.h>
>  #include <linux/platform_device.h>
>  #include <linux/err.h>
> +#include <linux/of.h>
>  
>  #include <linux/platform_data/ntc_thermistor.h>
>  
> @@ -37,6 +38,41 @@ struct ntc_compensation {
>  	unsigned int	ohm;
>  };
>  
> +static const struct platform_device_id ntc_thermistor_id[] = {
> +	{ "ncp15wb473", TYPE_NCPXXWB473 },
> +	{ "ncp18wb473", TYPE_NCPXXWB473 },
> +	{ "ncp21wb473", TYPE_NCPXXWB473 },
> +	{ "ncp03wb473", TYPE_NCPXXWB473 },
> +	{ "ncp15wl333", TYPE_NCPXXWL333 },
> +	{ },
> +};
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id ntc_match[] = {
> +	{ .compatible = "ntc,ncp15wb473", .data = (void *)TYPE_NCPXXWB473 },
> +	{ .compatible = "ntc,ncp18wb473", .data = (void *)TYPE_NCPXXWB473 },
> +	{ .compatible = "ntc,ncp21wb473", .data = (void *)TYPE_NCPXXWB473 },
> +	{ .compatible = "ntc,ncp03wb473", .data = (void *)TYPE_NCPXXWB473 },
> +	{ .compatible = "ntc,ncp15wl333", .data = (void *)TYPE_NCPXXWL333 },

Better point to ntc_thermistor_id[TYPE_xxx]. See below.

> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, ntc_match);
> +#endif
> +
> +/* Get NTC type either from device tree or platform data. */
> +static enum ntc_thermistor_type thermistor_get_type
> +				(struct platform_device *pdev)
> +{
> +	if (pdev->dev.of_node) {
> +		const struct of_device_id *match;
> +		match = of_match_node(of_match_ptr(ntc_match),
> +						pdev->dev.of_node);
> +		return (unsigned int)match->data;
> +	}
> +
> +	return platform_get_device_id(pdev)->driver_data;
> +}
> +
>  /*
>   * A compensation table should be sorted by the values of .ohm
>   * in descending order.
> @@ -126,6 +162,27 @@ struct ntc_data {
>  	char name[PLATFORM_NAME_SIZE];
>  };
>  
> +#ifdef CONFIG_OF

Please merge the two CONFIG_OF blocks into one.

> +static void ntc_thermistor_parse_dt(struct ntc_thermistor_platform_data *pdata,
> +							struct device_node *np)
> +{
> +	of_property_read_u32(np, "pullup-uV", &pdata->pullup_uV);
> +	of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm);
> +	of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm);
> +	if (of_find_property(np, "connected-positive", NULL))
> +		pdata->connect = NTC_CONNECTED_POSITIVE;
> +	else /* status change should be possible if not always on. */
> +		pdata->connect = NTC_CONNECTED_GROUND;
> +}
> +#else
> +static void
> +static void ntc_thermistor_parse_dt(struct ntc_thermistor_platform_data *pdata,
> +							struct device_node *np)
> +{
> +	return;

Unnecessary return statement.

> +}
> +#endif
> +
>  static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
>  {
>  	if (divisor == 0 && dividend == 0)
> @@ -313,9 +370,19 @@ static const struct attribute_group ntc_attr_group = {
>  static int ntc_thermistor_probe(struct platform_device *pdev)
>  {
>  	struct ntc_data *data;
> -	struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct ntc_thermistor_platform_data *pdata = NULL;

Unnecessary change. It doesn't hurt if pdata is initialized to non-NULL, and
initializing it to NULL is unnecessary anyway since it is always assigned below.

>  	int ret = 0;
>  
> +	if (np) {
> +		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +		if (!pdata)
> +			return -ENOMEM;
> +
> +		ntc_thermistor_parse_dt(pdata, np);

This compiles, but the resulting code would not work as the necessary fields
in pdata are not all filled out. So I think it would be better to merge the code
with the next patch, as both don't really work independently.

> +	} else
> +		pdata = pdev->dev.platform_data;

Not necessary if you keep above pre-initialization.

A better idea would be to move the devm_kzalloc into ntc_thermistor_parse_dt
and return a pointer to pdata from it. Then you would have

	pdata = ntc_thermistor_parse_dt(np);
	if (!pdata)
		pdata = pdev->dev.platform_data;

The check for np == NULL could then also be in ntc_thermistor_parse_dt and only
be executed if CONFIG_OF is defined. This would make the code flow look much nicer. 

> +
>  	if (!pdata) {
>  		dev_err(&pdev->dev, "No platform init data supplied.\n");
>  		return -ENODEV;
> @@ -353,9 +420,9 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
>  	data->dev = &pdev->dev;
>  	data->pdev = pdev;
>  	data->pdata = pdata;
> -	strlcpy(data->name, pdev->id_entry->name, sizeof(data->name));
> +	strncpy(data->name, dev_name(&pdev->dev), PLATFORM_NAME_SIZE);
>  
strlcpy is used to ensure 0 termination.
sizeof(data->name) is used to ensure object size.

You should introduce a variable such as pdev_id and either assign pdev->id_entry
or the result of the of function call to it. Other code does that for example
with
	const struct of_device_id *of_id =
	                        of_match_device(of_match_ptr(coda_dt_ids),
				&pdev->dev);
	const struct platform_device_id *pdev_id;
	...
	pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);

and then just use pdev_id. Then you can use
	strncpy(data->name, pdev_id->name, sizeof(data->name));

That requires to change .data in the of_device_id table to point to the
platform_device_id.

> -	switch (pdev->id_entry->driver_data) {
> +	switch (thermistor_get_type(pdev)) {

And then:
	switch (pdev_id) {

>  	case TYPE_NCPXXWB473:
>  		data->comp = ncpXXwb473;
>  		data->n_comp = ARRAY_SIZE(ncpXXwb473);
> @@ -365,9 +432,8 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
>  		data->n_comp = ARRAY_SIZE(ncpXXwl333);
>  		break;
>  	default:
> -		dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
> -				pdev->id_entry->driver_data,
> -				pdev->id_entry->name);
> +		dev_err(&pdev->dev, "Unknown device type: %u\n",
> +				thermistor_get_type(pdev));

		dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
			pdev_id->driver_data,
			pdev_id->name);

>  		return -EINVAL;
>  	}
>  
> @@ -386,9 +452,8 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
>  		goto err_after_sysfs;
>  	}
>  
> -	dev_info(&pdev->dev, "Thermistor %s:%d (type: %s/%lu) successfully probed.\n",
> -			pdev->name, pdev->id, pdev->id_entry->name,
> -			pdev->id_entry->driver_data);
> +	dev_info(&pdev->dev, "Thermistor successfully probed.\n");

Same here again.
	dev_info(&pdev->dev, "Thermistor %s:%d (type: %s/%lu) successfully probed.\n",
		 pdev->name, pdev->id, pdev_id->name,
		 pdev_id->driver_data);

Though I would change that to
	dev_info(&pdev->dev, "Thermistor type %s successfully probed.\n",
		 pdev_id->name);

since the rest of the output is either redundant (name/id) or internal
(pdev_id->driver_data).

> +
>  	return 0;
>  err_after_sysfs:
>  	sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
> @@ -406,19 +471,11 @@ static int ntc_thermistor_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> -static const struct platform_device_id ntc_thermistor_id[] = {
> -	{ "ncp15wb473", TYPE_NCPXXWB473 },
> -	{ "ncp18wb473", TYPE_NCPXXWB473 },
> -	{ "ncp21wb473", TYPE_NCPXXWB473 },
> -	{ "ncp03wb473", TYPE_NCPXXWB473 },
> -	{ "ncp15wl333", TYPE_NCPXXWL333 },
> -	{ },
> -};
> -
>  static struct platform_driver ntc_thermistor_driver = {
>  	.driver = {
>  		.name = "ntc-thermistor",
>  		.owner = THIS_MODULE,
> +		.of_match_table = of_match_ptr(ntc_match),
>  	},
>  	.probe = ntc_thermistor_probe,
>  	.remove = ntc_thermistor_remove,
> -- 
> 1.7.9.5
> 
> 


More information about the devicetree-discuss mailing list