Commit 024913db authored by Uwe Kleine-König's avatar Uwe Kleine-König

pwm: Provide pwmchip_alloc() function and a devm variant of it

This function allocates a struct pwm_chip and driver data. Compared to
the status quo the split into pwm_chip and driver data is new, otherwise
it doesn't change anything relevant (yet).

The intention is that after all drivers are switched to use this
allocation function, its possible to add a struct device to struct
pwm_chip to properly track the latter's lifetime without touching all
drivers again. Proper lifetime tracking is a necessary precondition to
introduce character device support for PWMs (that implements atomic
setting and doesn't suffer from the sysfs overhead of the /sys/class/pwm
userspace support).

The new function pwmchip_priv() (obviously?) only works for chips
allocated with pwmchip_alloc().

Link: https://lore.kernel.org/r/9577d6053a5a52536057dc8654ff567181c2da82.1707900770.git.u.kleine-koenig@pengutronix.deSigned-off-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
parent 24003d50
...@@ -420,6 +420,7 @@ POWER ...@@ -420,6 +420,7 @@ POWER
devm_reboot_mode_unregister() devm_reboot_mode_unregister()
PWM PWM
devm_pwmchip_alloc()
devm_pwmchip_add() devm_pwmchip_add()
devm_pwm_get() devm_pwm_get()
devm_fwnode_pwm_get() devm_fwnode_pwm_get()
......
...@@ -143,11 +143,12 @@ to implement the pwm_*() functions itself. This means that it's impossible ...@@ -143,11 +143,12 @@ to implement the pwm_*() functions itself. This means that it's impossible
to have multiple PWM drivers in the system. For this reason it's mandatory to have multiple PWM drivers in the system. For this reason it's mandatory
for new drivers to use the generic PWM framework. for new drivers to use the generic PWM framework.
A new PWM controller/chip can be added using pwmchip_add() and removed A new PWM controller/chip can be allocated using pwmchip_alloc(), then
again with pwmchip_remove(). pwmchip_add() takes a filled in struct registered using pwmchip_add() and removed again with pwmchip_remove(). To undo
pwm_chip as argument which provides a description of the PWM chip, the pwmchip_alloc() use pwmchip_put(). pwmchip_add() takes a filled in struct
number of PWM devices provided by the chip and the chip-specific pwm_chip as argument which provides a description of the PWM chip, the number
implementation of the supported PWM operations to the framework. of PWM devices provided by the chip and the chip-specific implementation of the
supported PWM operations to the framework.
When implementing polarity support in a PWM driver, make sure to respect the When implementing polarity support in a PWM driver, make sure to respect the
signal conventions in the PWM framework. By definition, normal polarity signal conventions in the PWM framework. By definition, normal polarity
......
...@@ -454,6 +454,64 @@ of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args) ...@@ -454,6 +454,64 @@ of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args)
} }
EXPORT_SYMBOL_GPL(of_pwm_single_xlate); EXPORT_SYMBOL_GPL(of_pwm_single_xlate);
#define PWMCHIP_ALIGN ARCH_DMA_MINALIGN
static void *pwmchip_priv(struct pwm_chip *chip)
{
return (void *)chip + ALIGN(sizeof(*chip), PWMCHIP_ALIGN);
}
/* This is the counterpart to pwmchip_alloc() */
void pwmchip_put(struct pwm_chip *chip)
{
kfree(chip);
}
EXPORT_SYMBOL_GPL(pwmchip_put);
struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
{
struct pwm_chip *chip;
size_t alloc_size;
alloc_size = size_add(ALIGN(sizeof(*chip), PWMCHIP_ALIGN), sizeof_priv);
chip = kzalloc(alloc_size, GFP_KERNEL);
if (!chip)
return ERR_PTR(-ENOMEM);
chip->dev = parent;
chip->npwm = npwm;
pwmchip_set_drvdata(chip, pwmchip_priv(chip));
return chip;
}
EXPORT_SYMBOL_GPL(pwmchip_alloc);
static void devm_pwmchip_put(void *data)
{
struct pwm_chip *chip = data;
pwmchip_put(chip);
}
struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
{
struct pwm_chip *chip;
int ret;
chip = pwmchip_alloc(parent, npwm, sizeof_priv);
if (IS_ERR(chip))
return chip;
ret = devm_add_action_or_reset(parent, devm_pwmchip_put, chip);
if (ret)
return ERR_PTR(ret);
return chip;
}
EXPORT_SYMBOL_GPL(devm_pwmchip_alloc);
static void of_pwmchip_add(struct pwm_chip *chip) static void of_pwmchip_add(struct pwm_chip *chip)
{ {
if (!pwmchip_parent(chip) || !pwmchip_parent(chip)->of_node) if (!pwmchip_parent(chip) || !pwmchip_parent(chip)->of_node)
......
...@@ -403,6 +403,10 @@ static inline bool pwm_might_sleep(struct pwm_device *pwm) ...@@ -403,6 +403,10 @@ static inline bool pwm_might_sleep(struct pwm_device *pwm)
int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
unsigned long timeout); unsigned long timeout);
void pwmchip_put(struct pwm_chip *chip);
struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv);
struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv);
int __pwmchip_add(struct pwm_chip *chip, struct module *owner); int __pwmchip_add(struct pwm_chip *chip, struct module *owner);
#define pwmchip_add(chip) __pwmchip_add(chip, THIS_MODULE) #define pwmchip_add(chip) __pwmchip_add(chip, THIS_MODULE)
void pwmchip_remove(struct pwm_chip *chip); void pwmchip_remove(struct pwm_chip *chip);
...@@ -475,6 +479,24 @@ static inline int pwm_capture(struct pwm_device *pwm, ...@@ -475,6 +479,24 @@ static inline int pwm_capture(struct pwm_device *pwm,
return -EINVAL; return -EINVAL;
} }
static inline void pwmchip_put(struct pwm_chip *chip)
{
}
static inline struct pwm_chip *pwmchip_alloc(struct device *parent,
unsigned int npwm,
size_t sizeof_priv)
{
return ERR_PTR(-EINVAL);
}
static inline struct pwm_chip *devm_pwmchip_alloc(struct device *parent,
unsigned int npwm,
size_t sizeof_priv)
{
return pwmchip_alloc(parent, npwm, sizeof_priv);
}
static inline int pwmchip_add(struct pwm_chip *chip) static inline int pwmchip_add(struct pwm_chip *chip)
{ {
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment