diff options
Diffstat (limited to 'drivers/pwm/core.c')
| -rw-r--r-- | drivers/pwm/core.c | 68 | 
1 files changed, 38 insertions, 30 deletions
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index d333e7422f4a..e01147f66e15 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -27,7 +27,10 @@  static DEFINE_MUTEX(pwm_lookup_lock);  static LIST_HEAD(pwm_lookup_list); + +/* protects access to pwm_chips, allocated_pwms, and pwm_tree */  static DEFINE_MUTEX(pwm_lock); +  static LIST_HEAD(pwm_chips);  static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);  static RADIX_TREE(pwm_tree, GFP_KERNEL); @@ -37,6 +40,7 @@ static struct pwm_device *pwm_to_device(unsigned int pwm)  	return radix_tree_lookup(&pwm_tree, pwm);  } +/* Called with pwm_lock held */  static int alloc_pwms(unsigned int count)  {  	unsigned int start; @@ -47,9 +51,12 @@ static int alloc_pwms(unsigned int count)  	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)  {  	unsigned int i; @@ -108,8 +115,13 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)  	}  	if (pwm->chip->ops->get_state) { -		pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state); -		trace_pwm_get(pwm, &pwm->state); +		struct pwm_state state; + +		err = pwm->chip->ops->get_state(pwm->chip, pwm, &state); +		trace_pwm_get(pwm, &state, err); + +		if (!err) +			pwm->state = state;  		if (IS_ENABLED(CONFIG_PWM_DEBUG))  			pwm->last = pwm->state; @@ -267,20 +279,21 @@ int pwmchip_add(struct pwm_chip *chip)  	if (!pwm_ops_check(chip))  		return -EINVAL; +	chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL); +	if (!chip->pwms) +		return -ENOMEM; +  	mutex_lock(&pwm_lock);  	ret = alloc_pwms(chip->npwm); -	if (ret < 0) -		goto out; +	if (ret < 0) { +		mutex_unlock(&pwm_lock); +		kfree(chip->pwms); +		return ret; +	}  	chip->base = ret; -	chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL); -	if (!chip->pwms) { -		ret = -ENOMEM; -		goto out; -	} -  	for (i = 0; i < chip->npwm; i++) {  		pwm = &chip->pwms[i]; @@ -291,23 +304,16 @@ int pwmchip_add(struct pwm_chip *chip)  		radix_tree_insert(&pwm_tree, pwm->pwm, pwm);  	} -	bitmap_set(allocated_pwms, chip->base, chip->npwm); - -	INIT_LIST_HEAD(&chip->list);  	list_add(&chip->list, &pwm_chips); -	ret = 0; +	mutex_unlock(&pwm_lock);  	if (IS_ENABLED(CONFIG_OF))  		of_pwmchip_add(chip); -out: -	mutex_unlock(&pwm_lock); - -	if (!ret) -		pwmchip_sysfs_export(chip); +	pwmchip_sysfs_export(chip); -	return ret; +	return 0;  }  EXPORT_SYMBOL_GPL(pwmchip_add); @@ -457,8 +463,11 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,  	 * checks.  	 */ -	chip->ops->get_state(chip, pwm, &s1); -	trace_pwm_get(pwm, &s1); +	err = chip->ops->get_state(chip, pwm, &s1); +	trace_pwm_get(pwm, &s1, err); +	if (err) +		/* If that failed there isn't much to debug */ +		return;  	/*  	 * The lowlevel driver either ignored .polarity (which is a bug) or as @@ -514,16 +523,17 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,  	/* reapply the state that the driver reported being configured. */  	err = chip->ops->apply(chip, pwm, &s1); +	trace_pwm_apply(pwm, &s1, err);  	if (err) {  		*last = s1;  		dev_err(chip->dev, "failed to reapply current setting\n");  		return;  	} -	trace_pwm_apply(pwm, &s1); - -	chip->ops->get_state(chip, pwm, last); -	trace_pwm_get(pwm, last); +	err = chip->ops->get_state(chip, pwm, last); +	trace_pwm_get(pwm, last, err); +	if (err) +		return;  	/* reapplication of the current state should give an exact match */  	if (s1.enabled != last->enabled || @@ -571,11 +581,10 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)  		return 0;  	err = chip->ops->apply(chip, pwm, state); +	trace_pwm_apply(pwm, state, err);  	if (err)  		return err; -	trace_pwm_apply(pwm, state); -  	pwm->state = *state;  	/* @@ -1179,8 +1188,7 @@ DEFINE_SEQ_ATTRIBUTE(pwm_debugfs);  static int __init pwm_debugfs_init(void)  { -	debugfs_create_file("pwm", S_IFREG | 0444, NULL, NULL, -			    &pwm_debugfs_fops); +	debugfs_create_file("pwm", 0444, NULL, NULL, &pwm_debugfs_fops);  	return 0;  }  | 
