mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
pwm: adp5585: add support for adp5589
Add support for the adp5589 I/O expander. From a PWM point of view it is pretty similar to adp5585. Main difference is the address of registers meaningful for configuring the PWM. Acked-by: Uwe Kleine-König <ukleinek@kernel.org> Signed-off-by: Nuno Sá <nuno.sa@analog.com> Link: https://lore.kernel.org/r/20250701-dev-adp5589-fw-v7-10-b1fcfe9e9826@analog.com Signed-off-by: Lee Jones <lee@kernel.org>
This commit is contained in:
parent
9f425bf713
commit
75024f97e8
2 changed files with 59 additions and 17 deletions
|
@ -33,21 +33,33 @@
|
|||
#define ADP5585_PWM_MIN_PERIOD_NS (2ULL * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ)
|
||||
#define ADP5585_PWM_MAX_PERIOD_NS (2ULL * 0xffff * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ)
|
||||
|
||||
struct adp5585_pwm_chip {
|
||||
unsigned int pwm_cfg;
|
||||
unsigned int pwm_offt_low;
|
||||
unsigned int pwm_ont_low;
|
||||
};
|
||||
|
||||
struct adp5585_pwm {
|
||||
const struct adp5585_pwm_chip *info;
|
||||
struct regmap *regmap;
|
||||
unsigned int ext_cfg;
|
||||
};
|
||||
|
||||
static int pwm_adp5585_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct regmap *regmap = pwmchip_get_drvdata(chip);
|
||||
struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
|
||||
|
||||
/* Configure the R3 pin as PWM output. */
|
||||
return regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C,
|
||||
return regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg,
|
||||
ADP5585_R3_EXTEND_CFG_MASK,
|
||||
ADP5585_R3_EXTEND_CFG_PWM_OUT);
|
||||
}
|
||||
|
||||
static void pwm_adp5585_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct regmap *regmap = pwmchip_get_drvdata(chip);
|
||||
struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
|
||||
|
||||
regmap_update_bits(regmap, ADP5585_PIN_CONFIG_C,
|
||||
regmap_update_bits(adp5585_pwm->regmap, adp5585_pwm->ext_cfg,
|
||||
ADP5585_R3_EXTEND_CFG_MASK,
|
||||
ADP5585_R3_EXTEND_CFG_GPIO4);
|
||||
}
|
||||
|
@ -56,14 +68,16 @@ static int pwm_adp5585_apply(struct pwm_chip *chip,
|
|||
struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct regmap *regmap = pwmchip_get_drvdata(chip);
|
||||
struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
|
||||
const struct adp5585_pwm_chip *info = adp5585_pwm->info;
|
||||
struct regmap *regmap = adp5585_pwm->regmap;
|
||||
u64 period, duty_cycle;
|
||||
u32 on, off;
|
||||
__le16 val;
|
||||
int ret;
|
||||
|
||||
if (!state->enabled) {
|
||||
regmap_clear_bits(regmap, ADP5585_PWM_CFG, ADP5585_PWM_EN);
|
||||
regmap_clear_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -84,41 +98,43 @@ static int pwm_adp5585_apply(struct pwm_chip *chip,
|
|||
off = div_u64(period, NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) - on;
|
||||
|
||||
val = cpu_to_le16(off);
|
||||
ret = regmap_bulk_write(regmap, ADP5585_PWM_OFFT_LOW, &val, 2);
|
||||
ret = regmap_bulk_write(regmap, info->pwm_offt_low, &val, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = cpu_to_le16(on);
|
||||
ret = regmap_bulk_write(regmap, ADP5585_PWM_ONT_LOW, &val, 2);
|
||||
ret = regmap_bulk_write(regmap, info->pwm_ont_low, &val, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable PWM in continuous mode and no external AND'ing. */
|
||||
ret = regmap_update_bits(regmap, ADP5585_PWM_CFG,
|
||||
ret = regmap_update_bits(regmap, info->pwm_cfg,
|
||||
ADP5585_PWM_IN_AND | ADP5585_PWM_MODE |
|
||||
ADP5585_PWM_EN, ADP5585_PWM_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_set_bits(regmap, ADP5585_PWM_CFG, ADP5585_PWM_EN);
|
||||
return regmap_set_bits(regmap, info->pwm_cfg, ADP5585_PWM_EN);
|
||||
}
|
||||
|
||||
static int pwm_adp5585_get_state(struct pwm_chip *chip,
|
||||
struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct regmap *regmap = pwmchip_get_drvdata(chip);
|
||||
struct adp5585_pwm *adp5585_pwm = pwmchip_get_drvdata(chip);
|
||||
const struct adp5585_pwm_chip *info = adp5585_pwm->info;
|
||||
struct regmap *regmap = adp5585_pwm->regmap;
|
||||
unsigned int on, off;
|
||||
unsigned int val;
|
||||
__le16 on_off;
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(regmap, ADP5585_PWM_OFFT_LOW, &on_off, 2);
|
||||
ret = regmap_bulk_read(regmap, info->pwm_offt_low, &on_off, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
off = le16_to_cpu(on_off);
|
||||
|
||||
ret = regmap_bulk_read(regmap, ADP5585_PWM_ONT_LOW, &on_off, 2);
|
||||
ret = regmap_bulk_read(regmap, info->pwm_ont_low, &on_off, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
on = le16_to_cpu(on_off);
|
||||
|
@ -128,7 +144,7 @@ static int pwm_adp5585_get_state(struct pwm_chip *chip,
|
|||
|
||||
state->polarity = PWM_POLARITY_NORMAL;
|
||||
|
||||
regmap_read(regmap, ADP5585_PWM_CFG, &val);
|
||||
regmap_read(regmap, info->pwm_cfg, &val);
|
||||
state->enabled = !!(val & ADP5585_PWM_EN);
|
||||
|
||||
return 0;
|
||||
|
@ -143,18 +159,28 @@ static const struct pwm_ops adp5585_pwm_ops = {
|
|||
|
||||
static int adp5585_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *id = platform_get_device_id(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct adp5585_dev *adp5585 = dev_get_drvdata(dev->parent);
|
||||
struct adp5585_pwm *adp5585_pwm;
|
||||
struct pwm_chip *chip;
|
||||
int ret;
|
||||
|
||||
chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM, 0);
|
||||
chip = devm_pwmchip_alloc(dev, ADP5585_PWM_CHAN_NUM,
|
||||
sizeof(*adp5585_pwm));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
|
||||
adp5585_pwm = pwmchip_get_drvdata(chip);
|
||||
adp5585_pwm->regmap = adp5585->regmap;
|
||||
adp5585_pwm->ext_cfg = adp5585->regs->ext_cfg;
|
||||
|
||||
adp5585_pwm->info = (const struct adp5585_pwm_chip *)id->driver_data;
|
||||
if (!adp5585_pwm->info)
|
||||
return -ENODEV;
|
||||
|
||||
device_set_of_node_from_dev(dev, dev->parent);
|
||||
|
||||
pwmchip_set_drvdata(chip, adp5585->regmap);
|
||||
chip->ops = &adp5585_pwm_ops;
|
||||
|
||||
ret = devm_pwmchip_add(dev, chip);
|
||||
|
@ -164,8 +190,21 @@ static int adp5585_pwm_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct adp5585_pwm_chip adp5589_pwm_chip_info = {
|
||||
.pwm_cfg = ADP5585_PWM_CFG,
|
||||
.pwm_offt_low = ADP5585_PWM_OFFT_LOW,
|
||||
.pwm_ont_low = ADP5585_PWM_ONT_LOW,
|
||||
};
|
||||
|
||||
static const struct adp5585_pwm_chip adp5585_pwm_chip_info = {
|
||||
.pwm_cfg = ADP5589_PWM_CFG,
|
||||
.pwm_offt_low = ADP5589_PWM_OFFT_LOW,
|
||||
.pwm_ont_low = ADP5589_PWM_ONT_LOW,
|
||||
};
|
||||
|
||||
static const struct platform_device_id adp5585_pwm_id_table[] = {
|
||||
{ "adp5585-pwm" },
|
||||
{ "adp5585-pwm", (kernel_ulong_t)&adp5585_pwm_chip_info },
|
||||
{ "adp5589-pwm", (kernel_ulong_t)&adp5589_pwm_chip_info },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, adp5585_pwm_id_table);
|
||||
|
|
|
@ -118,6 +118,9 @@
|
|||
#define ADP5589_GPO_DATA_OUT_A 0x2a
|
||||
#define ADP5589_GPO_OUT_MODE_A 0x2d
|
||||
#define ADP5589_GPIO_DIRECTION_A 0x30
|
||||
#define ADP5589_PWM_OFFT_LOW 0x3e
|
||||
#define ADP5589_PWM_ONT_LOW 0x40
|
||||
#define ADP5589_PWM_CFG 0x42
|
||||
#define ADP5589_PIN_CONFIG_D 0x4C
|
||||
#define ADP5589_INT_EN 0x4e
|
||||
#define ADP5589_MAX_REG ADP5589_INT_EN
|
||||
|
|
Loading…
Add table
Reference in a new issue