pwm: Replace PWM chip unique base by unique ID

Traditionally each PWM device had a unique ID stored in the "pwm" member
of struct pwm_device. However this number was hardly used and dropped
in the previous commit. To identify a certain PWM you're supposed to use
the chip's ID and the hwpwm of the PWM device now.

With the PWM chip base gone PWM chips can get their IDs better and
simpler using an idr.

This is expected to change the numbering of PWM chips, but nothing
should rely on the numbering anyhow.

Other than that the side effects are:

 - The PWM chip IDs are smaller and in most cases consecutive.
 - The ordering in /sys/kernel/debug/pwm is ordered by ascending PWM
   chip ID.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
This commit is contained in:
Uwe Kleine-König 2023-11-14 12:20:12 +01:00 committed by Thierry Reding
parent f3e25e68ce
commit 54c86dd20b
3 changed files with 27 additions and 45 deletions

View file

@ -8,6 +8,7 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/of.h>
#include <linux/pwm.h>
#include <linux/list.h>
@ -23,52 +24,25 @@
#define CREATE_TRACE_POINTS
#include <trace/events/pwm.h>
#define MAX_PWMS 1024
static DEFINE_MUTEX(pwm_lookup_lock);
static LIST_HEAD(pwm_lookup_list);
/* protects access to pwm_chips and allocated_pwms */
/* protects access to pwm_chips */
static DEFINE_MUTEX(pwm_lock);
static LIST_HEAD(pwm_chips);
static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
/* Called with pwm_lock held */
static int alloc_pwms(unsigned int count)
{
unsigned int start;
start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, 0,
count, 0);
if (start + count > MAX_PWMS)
return -ENOSPC;
bitmap_set(allocated_pwms, start, count);
return start;
}
/* Called with pwm_lock held */
static void free_pwms(struct pwm_chip *chip)
{
bitmap_clear(allocated_pwms, chip->base, chip->npwm);
kfree(chip->pwms);
chip->pwms = NULL;
}
static DEFINE_IDR(pwm_chips);
static struct pwm_chip *pwmchip_find_by_name(const char *name)
{
struct pwm_chip *chip;
unsigned long id, tmp;
if (!name)
return NULL;
mutex_lock(&pwm_lock);
list_for_each_entry(chip, &pwm_chips, list) {
idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) {
const char *chip_name = dev_name(chip->dev);
if (chip_name && strcmp(chip_name, name) == 0) {
@ -252,14 +226,14 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
mutex_lock(&pwm_lock);
ret = alloc_pwms(chip->npwm);
ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL);
if (ret < 0) {
mutex_unlock(&pwm_lock);
kfree(chip->pwms);
return ret;
}
chip->base = ret;
chip->id = ret;
for (i = 0; i < chip->npwm; i++) {
pwm = &chip->pwms[i];
@ -268,8 +242,6 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
pwm->hwpwm = i;
}
list_add(&chip->list, &pwm_chips);
mutex_unlock(&pwm_lock);
if (IS_ENABLED(CONFIG_OF))
@ -296,11 +268,11 @@ void pwmchip_remove(struct pwm_chip *chip)
mutex_lock(&pwm_lock);
list_del_init(&chip->list);
free_pwms(chip);
idr_remove(&pwm_chips, chip->id);
mutex_unlock(&pwm_lock);
kfree(chip->pwms);
}
EXPORT_SYMBOL_GPL(pwmchip_remove);
@ -596,10 +568,11 @@ EXPORT_SYMBOL_GPL(pwm_adjust_config);
static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode)
{
struct pwm_chip *chip;
unsigned long id, tmp;
mutex_lock(&pwm_lock);
list_for_each_entry(chip, &pwm_chips, list)
idr_for_each_entry_ul(&pwm_chips, chip, tmp, id)
if (chip->dev && device_match_fwnode(chip->dev, fwnode)) {
mutex_unlock(&pwm_lock);
return chip;
@ -1057,17 +1030,27 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
static void *pwm_seq_start(struct seq_file *s, loff_t *pos)
{
unsigned long id = *pos;
void *ret;
mutex_lock(&pwm_lock);
s->private = "";
return seq_list_start(&pwm_chips, *pos);
ret = idr_get_next_ul(&pwm_chips, &id);
*pos = id;
return ret;
}
static void *pwm_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
unsigned long id = *pos + 1;
void *ret;
s->private = "\n";
return seq_list_next(v, &pwm_chips, pos);
ret = idr_get_next_ul(&pwm_chips, &id);
*pos = id;
return ret;
}
static void pwm_seq_stop(struct seq_file *s, void *v)
@ -1077,7 +1060,7 @@ static void pwm_seq_stop(struct seq_file *s, void *v)
static int pwm_seq_show(struct seq_file *s, void *v)
{
struct pwm_chip *chip = list_entry(v, struct pwm_chip, list);
struct pwm_chip *chip = v;
seq_printf(s, "%s%s/%s, %d PWM device%s\n", (char *)s->private,
chip->dev->bus ? chip->dev->bus->name : "no-bus",

View file

@ -510,7 +510,7 @@ void pwmchip_sysfs_export(struct pwm_chip *chip)
* the kernel it's just not exported.
*/
parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
"pwmchip%d", chip->base);
"pwmchip%d", chip->id);
if (IS_ERR(parent)) {
dev_warn(chip->dev,
"device_create failed for pwm_chip sysfs export\n");

View file

@ -292,7 +292,7 @@ struct pwm_chip {
struct device *dev;
const struct pwm_ops *ops;
struct module *owner;
int base;
unsigned int id;
unsigned int npwm;
struct pwm_device * (*of_xlate)(struct pwm_chip *chip,
@ -300,7 +300,6 @@ struct pwm_chip {
unsigned int of_pwm_n_cells;
/* only used internally by the PWM framework */
struct list_head list;
struct pwm_device *pwms;
};