mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-06 05:02:31 +00:00
pwm: Changes for v6.7-rc1
This contains a few fixes and a bunch of cleanups, a lot of which is in preparation for Uwe's character device support that may be ready in time for the next merge window. -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEEiOrDCAFJzPfAjcif3SOs138+s6EFAmVLhGsZHHRoaWVycnku cmVkaW5nQGdtYWlsLmNvbQAKCRDdI6zXfz6zoazOD/oDjIcP4lSkAdcRLuEPsHor 47INsdzm84g7CcUhFVY8a1ODjXNtVWcoXeLsJ69lJ3CJW9cjHlUaeFcP5KW5YhMN nE3Kk8MsAyeaN6QgSVeqsMj8t64WvUve3/M0M/bmaPt3mO8hxYTuSQlK5v+JfEyO Px8JH/U2f7W2zdVbdK3YtpcRtMiqYlYw2mu/ILumlZhZvxXEPWPs6lH8J3VHW9nU L8Up1dQB7TQcZiw4M2cdP/oSieQ+2PhWKbyWxdutArNxdMlE6xDurzIDzvwXL5kt cMWZtU0/kPu9cuH+19wqvRyFgGHSCjvP/smuu87/JvHc3Nbjxt//H3bQuDFLyiGc ZPfyNJOQ4vGSQ9gHQbedEsBnnX9qeZZecrd9PteUAqbAuRh/53bij0buXvzIwWzr 36/nHyjO9oEDcXgxGI75ATd7yd51ipyIEmYmzDGWoUGF8TK61wUYVaI0+x6I8JFO vQu1/pxcwjnQ/4r87opmx7E1UK/v5hYugpZIA39d5yM2djikZTTcNEhQchnN0RHN ih8ZyQ/A0XGHr2ICRFsgTPVFzKM0JyjCCVGvuEdkEN2dtk4dJlJTPz0xpNRIaALU dhsqziUT0FqqeLprwKBWjXZLbzWwwXWrOzAbbsXkoPny8BRYE60Pp5qqjPrLgj5Z 2z8rCDBaoILeFl5utV0rzw== =S2DI -----END PGP SIGNATURE----- Merge tag 'pwm/for-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm Pull pwm updates from Thierry Reding: "This contains a few fixes and a bunch of cleanups, a lot of which is in preparation for Uwe's character device support that may be ready in time for the next merge window" * tag 'pwm/for-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (37 commits) pwm: samsung: Document new member .channel in struct samsung_pwm_chip pwm: bcm2835: Add support for suspend/resume pwm: brcmstb: Checked clk_prepare_enable() return value pwm: brcmstb: Utilize appropriate clock APIs in suspend/resume pwm: pxa: Explicitly include correct DT includes pwm: cros-ec: Simplify using devm_pwmchip_add() and dev_err_probe() pwm: samsung: Consistently use the same name for driver data pwm: vt8500: Simplify using devm functions pwm: sprd: Simplify using devm_pwmchip_add() and dev_err_probe() pwm: sprd: Provide a helper to cast a chip to driver data pwm: spear: Simplify using devm functions pwm: mtk-disp: Simplify using devm_pwmchip_add() pwm: imx-tpm: Simplify using devm functions pwm: brcmstb: Simplify using devm functions pwm: bcm2835: Simplify using devm functions pwm: bcm-iproc: Simplify using devm functions pwm: Adapt sysfs API documentation to reality pwm: dwc: add PWM bit unset in get_state call pwm: dwc: make timer clock configurable pwm: dwc: split pci out of core driver ...
This commit is contained in:
commit
f3bfe64330
@ -15,12 +15,19 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx23-pwm
|
||||
oneOf:
|
||||
- const: fsl,imx23-pwm
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx28-pwm
|
||||
- const: fsl,imx23-pwm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
"#pwm-cells":
|
||||
const: 3
|
||||
|
||||
@ -31,6 +38,7 @@ properties:
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- fsl,pwm-number
|
||||
|
||||
additionalProperties: false
|
||||
@ -40,6 +48,7 @@ examples:
|
||||
pwm@80064000 {
|
||||
compatible = "fsl,imx23-pwm";
|
||||
reg = <0x80064000 0x2000>;
|
||||
clocks = <&clks 30>;
|
||||
#pwm-cells = <3>;
|
||||
fsl,pwm-number = <8>;
|
||||
};
|
||||
|
@ -757,7 +757,6 @@ static const struct pwm_ops mvebu_pwm_ops = {
|
||||
.free = mvebu_pwm_free,
|
||||
.get_state = mvebu_pwm_get_state,
|
||||
.apply = mvebu_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
|
||||
|
@ -1580,7 +1580,6 @@ static const struct pwm_ops ti_sn_pwm_ops = {
|
||||
.free = ti_sn_pwm_free,
|
||||
.apply = ti_sn_pwm_apply,
|
||||
.get_state = ti_sn_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ti_sn_pwm_probe(struct auxiliary_device *adev,
|
||||
|
@ -1085,7 +1085,6 @@ static const struct pwm_ops lpg_pwm_ops = {
|
||||
.request = lpg_pwm_request,
|
||||
.apply = lpg_pwm_apply,
|
||||
.get_state = lpg_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int lpg_add_pwm(struct lpg *lpg)
|
||||
|
@ -173,8 +173,8 @@ config PWM_CLPS711X
|
||||
will be called pwm-clps711x.
|
||||
|
||||
config PWM_CRC
|
||||
bool "Intel Crystalcove (CRC) PWM support"
|
||||
depends on X86 && INTEL_SOC_PMIC
|
||||
tristate "Intel Crystalcove (CRC) PWM support"
|
||||
depends on INTEL_SOC_PMIC
|
||||
help
|
||||
Generic PWM framework driver for Crystalcove (CRC) PMIC based PWM
|
||||
control.
|
||||
@ -186,9 +186,19 @@ config PWM_CROS_EC
|
||||
PWM driver for exposing a PWM attached to the ChromeOS Embedded
|
||||
Controller.
|
||||
|
||||
config PWM_DWC_CORE
|
||||
tristate
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
PWM driver for Synopsys DWC PWM Controller.
|
||||
|
||||
To compile this driver as a module, build the dependecies as
|
||||
modules, this will be called pwm-dwc-core.
|
||||
|
||||
config PWM_DWC
|
||||
tristate "DesignWare PWM Controller"
|
||||
depends on PCI
|
||||
tristate "DesignWare PWM Controller (PCI bus)"
|
||||
depends on HAS_IOMEM && PCI
|
||||
select PWM_DWC_CORE
|
||||
help
|
||||
PWM driver for Synopsys DWC PWM Controller attached to a PCI bus.
|
||||
|
||||
@ -407,7 +417,7 @@ config PWM_MEDIATEK
|
||||
|
||||
config PWM_MICROCHIP_CORE
|
||||
tristate "Microchip corePWM PWM support"
|
||||
depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST
|
||||
depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST
|
||||
depends on HAS_IOMEM && OF
|
||||
help
|
||||
PWM driver for Microchip FPGA soft IP core.
|
||||
|
@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CLK) += pwm-clk.o
|
||||
obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
|
||||
obj-$(CONFIG_PWM_CRC) += pwm-crc.o
|
||||
obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o
|
||||
obj-$(CONFIG_PWM_DWC_CORE) += pwm-dwc-core.o
|
||||
obj-$(CONFIG_PWM_DWC) += pwm-dwc.o
|
||||
obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
|
||||
obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
|
||||
|
@ -89,13 +89,13 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
|
||||
if (test_bit(PWMF_REQUESTED, &pwm->flags))
|
||||
return -EBUSY;
|
||||
|
||||
if (!try_module_get(pwm->chip->ops->owner))
|
||||
if (!try_module_get(pwm->chip->owner))
|
||||
return -ENODEV;
|
||||
|
||||
if (pwm->chip->ops->request) {
|
||||
err = pwm->chip->ops->request(pwm->chip, pwm);
|
||||
if (err) {
|
||||
module_put(pwm->chip->ops->owner);
|
||||
module_put(pwm->chip->owner);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@ -208,36 +208,6 @@ static void of_pwmchip_remove(struct pwm_chip *chip)
|
||||
of_node_put(chip->dev->of_node);
|
||||
}
|
||||
|
||||
/**
|
||||
* pwm_set_chip_data() - set private chip data for a PWM
|
||||
* @pwm: PWM device
|
||||
* @data: pointer to chip-specific data
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int pwm_set_chip_data(struct pwm_device *pwm, void *data)
|
||||
{
|
||||
if (!pwm)
|
||||
return -EINVAL;
|
||||
|
||||
pwm->chip_data = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_set_chip_data);
|
||||
|
||||
/**
|
||||
* pwm_get_chip_data() - get private chip data for a PWM
|
||||
* @pwm: PWM device
|
||||
*
|
||||
* Returns: A pointer to the chip-private data for the PWM device.
|
||||
*/
|
||||
void *pwm_get_chip_data(struct pwm_device *pwm)
|
||||
{
|
||||
return pwm ? pwm->chip_data : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_get_chip_data);
|
||||
|
||||
static bool pwm_ops_check(const struct pwm_chip *chip)
|
||||
{
|
||||
const struct pwm_ops *ops = chip->ops;
|
||||
@ -253,14 +223,16 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
|
||||
}
|
||||
|
||||
/**
|
||||
* pwmchip_add() - register a new PWM chip
|
||||
* __pwmchip_add() - register a new PWM chip
|
||||
* @chip: the PWM chip to add
|
||||
* @owner: reference to the module providing the chip.
|
||||
*
|
||||
* Register a new PWM chip.
|
||||
* Register a new PWM chip. @owner is supposed to be THIS_MODULE, use the
|
||||
* pwmchip_add wrapper to do this right.
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int pwmchip_add(struct pwm_chip *chip)
|
||||
int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
unsigned int i;
|
||||
@ -272,6 +244,8 @@ int pwmchip_add(struct pwm_chip *chip)
|
||||
if (!pwm_ops_check(chip))
|
||||
return -EINVAL;
|
||||
|
||||
chip->owner = owner;
|
||||
|
||||
chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL);
|
||||
if (!chip->pwms)
|
||||
return -ENOMEM;
|
||||
@ -306,7 +280,7 @@ int pwmchip_add(struct pwm_chip *chip)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwmchip_add);
|
||||
EXPORT_SYMBOL_GPL(__pwmchip_add);
|
||||
|
||||
/**
|
||||
* pwmchip_remove() - remove a PWM chip
|
||||
@ -338,17 +312,17 @@ static void devm_pwmchip_remove(void *data)
|
||||
pwmchip_remove(chip);
|
||||
}
|
||||
|
||||
int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip)
|
||||
int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pwmchip_add(chip);
|
||||
ret = __pwmchip_add(chip, owner);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pwmchip_add);
|
||||
EXPORT_SYMBOL_GPL(__devm_pwmchip_add);
|
||||
|
||||
/**
|
||||
* pwm_request_from_chip() - request a PWM device relative to a PWM chip
|
||||
@ -976,10 +950,9 @@ void pwm_put(struct pwm_device *pwm)
|
||||
if (pwm->chip->ops->free)
|
||||
pwm->chip->ops->free(pwm->chip, pwm);
|
||||
|
||||
pwm_set_chip_data(pwm, NULL);
|
||||
pwm->label = NULL;
|
||||
|
||||
module_put(pwm->chip->ops->owner);
|
||||
module_put(pwm->chip->owner);
|
||||
out:
|
||||
mutex_unlock(&pwm_lock);
|
||||
}
|
||||
|
@ -181,7 +181,6 @@ static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops ab8500_pwm_ops = {
|
||||
.apply = ab8500_pwm_apply,
|
||||
.get_state = ab8500_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ab8500_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -99,7 +99,6 @@ static int apple_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops apple_pwm_ops = {
|
||||
.apply = apple_pwm_apply,
|
||||
.get_state = apple_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int apple_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -170,7 +170,6 @@ static int atmel_hlcdc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops atmel_hlcdc_pwm_ops = {
|
||||
.apply = atmel_hlcdc_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_at91sam9x5_errata = {
|
||||
|
@ -364,7 +364,6 @@ static const struct pwm_ops atmel_tcb_pwm_ops = {
|
||||
.request = atmel_tcb_pwm_request,
|
||||
.free = atmel_tcb_pwm_free,
|
||||
.apply = atmel_tcb_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct atmel_tcb_config tcb_rm9200_config = {
|
||||
|
@ -402,7 +402,6 @@ static int atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops atmel_pwm_ops = {
|
||||
.apply = atmel_pwm_apply,
|
||||
.get_state = atmel_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct atmel_pwm_data atmel_sam9rl_pwm_data = {
|
||||
@ -547,7 +546,7 @@ static int atmel_pwm_probe(struct platform_device *pdev)
|
||||
static struct platform_driver atmel_pwm_driver = {
|
||||
.driver = {
|
||||
.name = "atmel-pwm",
|
||||
.of_match_table = of_match_ptr(atmel_pwm_dt_ids),
|
||||
.of_match_table = atmel_pwm_dt_ids,
|
||||
},
|
||||
.probe = atmel_pwm_probe,
|
||||
};
|
||||
|
@ -183,7 +183,6 @@ static int iproc_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops iproc_pwm_ops = {
|
||||
.apply = iproc_pwmc_apply,
|
||||
.get_state = iproc_pwmc_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int iproc_pwmc_probe(struct platform_device *pdev)
|
||||
@ -207,18 +206,10 @@ static int iproc_pwmc_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(ip->base))
|
||||
return PTR_ERR(ip->base);
|
||||
|
||||
ip->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(ip->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock: %ld\n",
|
||||
PTR_ERR(ip->clk));
|
||||
return PTR_ERR(ip->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ip->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ip->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(ip->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(ip->clk),
|
||||
"failed to get clock\n");
|
||||
|
||||
/* Set full drive and normal polarity for all channels */
|
||||
value = readl(ip->base + IPROC_PWM_CTRL_OFFSET);
|
||||
@ -230,22 +221,12 @@ static int iproc_pwmc_probe(struct platform_device *pdev)
|
||||
|
||||
writel(value, ip->base + IPROC_PWM_CTRL_OFFSET);
|
||||
|
||||
ret = pwmchip_add(&ip->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
clk_disable_unprepare(ip->clk);
|
||||
}
|
||||
ret = devm_pwmchip_add(&pdev->dev, &ip->chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to add PWM chip\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iproc_pwmc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iproc_pwmc *ip = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&ip->chip);
|
||||
|
||||
clk_disable_unprepare(ip->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm_iproc_pwmc_dt[] = {
|
||||
@ -260,7 +241,6 @@ static struct platform_driver iproc_pwmc_driver = {
|
||||
.of_match_table = bcm_iproc_pwmc_dt,
|
||||
},
|
||||
.probe = iproc_pwmc_probe,
|
||||
.remove_new = iproc_pwmc_remove,
|
||||
};
|
||||
module_platform_driver(iproc_pwmc_driver);
|
||||
|
||||
|
@ -269,7 +269,6 @@ static int kona_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops kona_pwm_ops = {
|
||||
.apply = kona_pwmc_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int kona_pwmc_probe(struct platform_device *pdev)
|
||||
|
@ -129,7 +129,6 @@ static const struct pwm_ops bcm2835_pwm_ops = {
|
||||
.request = bcm2835_pwm_request,
|
||||
.free = bcm2835_pwm_free,
|
||||
.apply = bcm2835_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int bcm2835_pwm_probe(struct platform_device *pdev)
|
||||
@ -147,41 +146,42 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(pc->base))
|
||||
return PTR_ERR(pc->base);
|
||||
|
||||
pc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
pc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(pc->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
|
||||
"clock not found\n");
|
||||
|
||||
ret = clk_prepare_enable(pc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &bcm2835_pwm_ops;
|
||||
pc->chip.npwm = 2;
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
|
||||
if (ret < 0)
|
||||
goto add_fail;
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to add pwmchip\n");
|
||||
|
||||
return 0;
|
||||
|
||||
add_fail:
|
||||
clk_disable_unprepare(pc->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bcm2835_pwm_remove(struct platform_device *pdev)
|
||||
static int bcm2835_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct bcm2835_pwm *pc = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&pc->chip);
|
||||
struct bcm2835_pwm *pc = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(pc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm2835_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct bcm2835_pwm *pc = dev_get_drvdata(dev);
|
||||
|
||||
return clk_prepare_enable(pc->clk);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(bcm2835_pwm_pm_ops, bcm2835_pwm_suspend,
|
||||
bcm2835_pwm_resume);
|
||||
|
||||
static const struct of_device_id bcm2835_pwm_of_match[] = {
|
||||
{ .compatible = "brcm,bcm2835-pwm", },
|
||||
{ /* sentinel */ }
|
||||
@ -192,9 +192,9 @@ static struct platform_driver bcm2835_pwm_driver = {
|
||||
.driver = {
|
||||
.name = "bcm2835-pwm",
|
||||
.of_match_table = bcm2835_pwm_of_match,
|
||||
.pm = pm_ptr(&bcm2835_pwm_pm_ops),
|
||||
},
|
||||
.probe = bcm2835_pwm_probe,
|
||||
.remove_new = bcm2835_pwm_remove,
|
||||
};
|
||||
module_platform_driver(bcm2835_pwm_driver);
|
||||
|
||||
|
@ -39,6 +39,8 @@
|
||||
#define BERLIN_PWM_TCNT 0xc
|
||||
#define BERLIN_PWM_MAX_TCNT 65535
|
||||
|
||||
#define BERLIN_PWM_NUMPWMS 4
|
||||
|
||||
struct berlin_pwm_channel {
|
||||
u32 enable;
|
||||
u32 ctrl;
|
||||
@ -50,6 +52,7 @@ struct berlin_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
struct berlin_pwm_channel channel[BERLIN_PWM_NUMPWMS];
|
||||
};
|
||||
|
||||
static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip)
|
||||
@ -70,24 +73,6 @@ static inline void berlin_pwm_writel(struct berlin_pwm_chip *bpc,
|
||||
writel_relaxed(value, bpc->base + channel * 0x10 + offset);
|
||||
}
|
||||
|
||||
static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct berlin_pwm_channel *channel;
|
||||
|
||||
channel = kzalloc(sizeof(*channel), GFP_KERNEL);
|
||||
if (!channel)
|
||||
return -ENOMEM;
|
||||
|
||||
return pwm_set_chip_data(pwm, channel);
|
||||
}
|
||||
|
||||
static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct berlin_pwm_channel *channel = pwm_get_chip_data(pwm);
|
||||
|
||||
kfree(channel);
|
||||
}
|
||||
|
||||
static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
u64 duty_ns, u64 period_ns)
|
||||
{
|
||||
@ -202,10 +187,7 @@ static int berlin_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
static const struct pwm_ops berlin_pwm_ops = {
|
||||
.request = berlin_pwm_request,
|
||||
.free = berlin_pwm_free,
|
||||
.apply = berlin_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id berlin_pwm_match[] = {
|
||||
@ -227,39 +209,23 @@ static int berlin_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(bpc->base))
|
||||
return PTR_ERR(bpc->base);
|
||||
|
||||
bpc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
bpc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(bpc->clk))
|
||||
return PTR_ERR(bpc->clk);
|
||||
|
||||
ret = clk_prepare_enable(bpc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bpc->chip.dev = &pdev->dev;
|
||||
bpc->chip.ops = &berlin_pwm_ops;
|
||||
bpc->chip.npwm = 4;
|
||||
bpc->chip.npwm = BERLIN_PWM_NUMPWMS;
|
||||
|
||||
ret = pwmchip_add(&bpc->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
clk_disable_unprepare(bpc->clk);
|
||||
return ret;
|
||||
}
|
||||
ret = devm_pwmchip_add(&pdev->dev, &bpc->chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
platform_set_drvdata(pdev, bpc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void berlin_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct berlin_pwm_chip *bpc = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&bpc->chip);
|
||||
|
||||
clk_disable_unprepare(bpc->clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int berlin_pwm_suspend(struct device *dev)
|
||||
{
|
||||
@ -267,11 +233,7 @@ static int berlin_pwm_suspend(struct device *dev)
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < bpc->chip.npwm; i++) {
|
||||
struct berlin_pwm_channel *channel;
|
||||
|
||||
channel = pwm_get_chip_data(&bpc->chip.pwms[i]);
|
||||
if (!channel)
|
||||
continue;
|
||||
struct berlin_pwm_channel *channel = &bpc->channel[i];
|
||||
|
||||
channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_ENABLE);
|
||||
channel->ctrl = berlin_pwm_readl(bpc, i, BERLIN_PWM_CONTROL);
|
||||
@ -295,11 +257,7 @@ static int berlin_pwm_resume(struct device *dev)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < bpc->chip.npwm; i++) {
|
||||
struct berlin_pwm_channel *channel;
|
||||
|
||||
channel = pwm_get_chip_data(&bpc->chip.pwms[i]);
|
||||
if (!channel)
|
||||
continue;
|
||||
struct berlin_pwm_channel *channel = &bpc->channel[i];
|
||||
|
||||
berlin_pwm_writel(bpc, i, channel->ctrl, BERLIN_PWM_CONTROL);
|
||||
berlin_pwm_writel(bpc, i, channel->duty, BERLIN_PWM_DUTY);
|
||||
@ -316,7 +274,6 @@ static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend,
|
||||
|
||||
static struct platform_driver berlin_pwm_driver = {
|
||||
.probe = berlin_pwm_probe,
|
||||
.remove_new = berlin_pwm_remove,
|
||||
.driver = {
|
||||
.name = "berlin-pwm",
|
||||
.of_match_table = berlin_pwm_match,
|
||||
|
@ -220,7 +220,6 @@ static int brcmstb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops brcmstb_pwm_ops = {
|
||||
.apply = brcmstb_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id brcmstb_pwm_of_match[] = {
|
||||
@ -238,17 +237,10 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
p->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(p->clk)) {
|
||||
dev_err(&pdev->dev, "failed to obtain clock\n");
|
||||
return PTR_ERR(p->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(p->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
p->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(p->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(p->clk),
|
||||
"failed to obtain clock\n");
|
||||
|
||||
platform_set_drvdata(pdev, p);
|
||||
|
||||
@ -257,30 +249,14 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
|
||||
p->chip.npwm = 2;
|
||||
|
||||
p->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(p->base)) {
|
||||
ret = PTR_ERR(p->base);
|
||||
goto out_clk;
|
||||
}
|
||||
if (IS_ERR(p->base))
|
||||
return PTR_ERR(p->base);
|
||||
|
||||
ret = pwmchip_add(&p->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
goto out_clk;
|
||||
}
|
||||
ret = devm_pwmchip_add(&pdev->dev, &p->chip);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out_clk:
|
||||
clk_disable_unprepare(p->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void brcmstb_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct brcmstb_pwm *p = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&p->chip);
|
||||
clk_disable_unprepare(p->clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -288,7 +264,7 @@ static int brcmstb_pwm_suspend(struct device *dev)
|
||||
{
|
||||
struct brcmstb_pwm *p = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable(p->clk);
|
||||
clk_disable_unprepare(p->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -297,9 +273,7 @@ static int brcmstb_pwm_resume(struct device *dev)
|
||||
{
|
||||
struct brcmstb_pwm *p = dev_get_drvdata(dev);
|
||||
|
||||
clk_enable(p->clk);
|
||||
|
||||
return 0;
|
||||
return clk_prepare_enable(p->clk);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -308,7 +282,6 @@ static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
|
||||
|
||||
static struct platform_driver brcmstb_pwm_driver = {
|
||||
.probe = brcmstb_pwm_probe,
|
||||
.remove_new = brcmstb_pwm_remove,
|
||||
.driver = {
|
||||
.name = "pwm-brcmstb",
|
||||
.of_match_table = brcmstb_pwm_of_match,
|
||||
|
@ -77,7 +77,6 @@ static int pwm_clk_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops pwm_clk_ops = {
|
||||
.apply = pwm_clk_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int pwm_clk_probe(struct platform_device *pdev)
|
||||
|
@ -72,7 +72,6 @@ static int clps711x_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops clps711x_pwm_ops = {
|
||||
.request = clps711x_pwm_request,
|
||||
.apply = clps711x_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct pwm_device *clps711x_pwm_xlate(struct pwm_chip *chip,
|
||||
|
@ -184,5 +184,8 @@ static struct platform_driver crystalcove_pwm_driver = {
|
||||
.name = "crystal_cove_pwm",
|
||||
},
|
||||
};
|
||||
module_platform_driver(crystalcove_pwm_driver);
|
||||
|
||||
builtin_platform_driver(crystalcove_pwm_driver);
|
||||
MODULE_ALIAS("platform:crystal_cove_pwm");
|
||||
MODULE_DESCRIPTION("Intel Crystalcove (CRC) PWM support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -22,12 +22,14 @@
|
||||
* @ec: Pointer to EC device
|
||||
* @chip: PWM controller chip
|
||||
* @use_pwm_type: Use PWM types instead of generic channels
|
||||
* @channel: array with per-channel data
|
||||
*/
|
||||
struct cros_ec_pwm_device {
|
||||
struct device *dev;
|
||||
struct cros_ec_device *ec;
|
||||
struct pwm_chip chip;
|
||||
bool use_pwm_type;
|
||||
struct cros_ec_pwm *channel;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -43,26 +45,6 @@ static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *chi
|
||||
return container_of(chip, struct cros_ec_pwm_device, chip);
|
||||
}
|
||||
|
||||
static int cros_ec_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct cros_ec_pwm *channel;
|
||||
|
||||
channel = kzalloc(sizeof(*channel), GFP_KERNEL);
|
||||
if (!channel)
|
||||
return -ENOMEM;
|
||||
|
||||
pwm_set_chip_data(pwm, channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cros_ec_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);
|
||||
|
||||
kfree(channel);
|
||||
}
|
||||
|
||||
static int cros_ec_dt_type_to_pwm_type(u8 dt_index, u8 *pwm_type)
|
||||
{
|
||||
switch (dt_index) {
|
||||
@ -158,7 +140,7 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
|
||||
struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);
|
||||
struct cros_ec_pwm *channel = &ec_pwm->channel[pwm->hwpwm];
|
||||
u16 duty_cycle;
|
||||
int ret;
|
||||
|
||||
@ -188,7 +170,7 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
|
||||
struct cros_ec_pwm *channel = pwm_get_chip_data(pwm);
|
||||
struct cros_ec_pwm *channel = &ec_pwm->channel[pwm->hwpwm];
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm);
|
||||
@ -237,11 +219,8 @@ cros_ec_pwm_xlate(struct pwm_chip *chip, const struct of_phandle_args *args)
|
||||
}
|
||||
|
||||
static const struct pwm_ops cros_ec_pwm_ops = {
|
||||
.request = cros_ec_pwm_request,
|
||||
.free = cros_ec_pwm_free,
|
||||
.get_state = cros_ec_pwm_get_state,
|
||||
.apply = cros_ec_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -286,10 +265,8 @@ static int cros_ec_pwm_probe(struct platform_device *pdev)
|
||||
struct pwm_chip *chip;
|
||||
int ret;
|
||||
|
||||
if (!ec) {
|
||||
dev_err(dev, "no parent EC device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!ec)
|
||||
return dev_err_probe(dev, -EINVAL, "no parent EC device\n");
|
||||
|
||||
ec_pwm = devm_kzalloc(dev, sizeof(*ec_pwm), GFP_KERNEL);
|
||||
if (!ec_pwm)
|
||||
@ -310,32 +287,23 @@ static int cros_ec_pwm_probe(struct platform_device *pdev)
|
||||
chip->npwm = CROS_EC_PWM_DT_COUNT;
|
||||
} else {
|
||||
ret = cros_ec_num_pwms(ec_pwm);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Couldn't find PWMs: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Couldn't find PWMs\n");
|
||||
chip->npwm = ret;
|
||||
}
|
||||
|
||||
ec_pwm->channel = devm_kcalloc(dev, chip->npwm, sizeof(*ec_pwm->channel),
|
||||
GFP_KERNEL);
|
||||
if (!ec_pwm->channel)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_dbg(dev, "Probed %u PWMs\n", chip->npwm);
|
||||
|
||||
ret = pwmchip_add(chip);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot register PWM: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = devm_pwmchip_add(dev, chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "cannot register PWM\n");
|
||||
|
||||
platform_set_drvdata(pdev, ec_pwm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cros_ec_pwm_remove(struct platform_device *dev)
|
||||
{
|
||||
struct cros_ec_pwm_device *ec_pwm = platform_get_drvdata(dev);
|
||||
struct pwm_chip *chip = &ec_pwm->chip;
|
||||
|
||||
pwmchip_remove(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
@ -349,7 +317,6 @@ MODULE_DEVICE_TABLE(of, cros_ec_pwm_of_match);
|
||||
|
||||
static struct platform_driver cros_ec_pwm_driver = {
|
||||
.probe = cros_ec_pwm_probe,
|
||||
.remove_new = cros_ec_pwm_remove,
|
||||
.driver = {
|
||||
.name = "cros-ec-pwm",
|
||||
.of_match_table = of_match_ptr(cros_ec_pwm_of_match),
|
||||
|
184
drivers/pwm/pwm-dwc-core.c
Normal file
184
drivers/pwm/pwm-dwc-core.c
Normal file
@ -0,0 +1,184 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DesignWare PWM Controller driver core
|
||||
*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* Author: Felipe Balbi (Intel)
|
||||
* Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
* Author: Raymond Tan <raymond.tan@intel.com>
|
||||
*/
|
||||
|
||||
#define DEFAULT_SYMBOL_NAMESPACE dwc_pwm
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pwm.h>
|
||||
|
||||
#include "pwm-dwc.h"
|
||||
|
||||
static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm));
|
||||
|
||||
if (enabled)
|
||||
reg |= DWC_TIM_CTRL_EN;
|
||||
else
|
||||
reg &= ~DWC_TIM_CTRL_EN;
|
||||
|
||||
dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm));
|
||||
}
|
||||
|
||||
static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc,
|
||||
struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
u64 tmp;
|
||||
u32 ctrl;
|
||||
u32 high;
|
||||
u32 low;
|
||||
|
||||
/*
|
||||
* Calculate width of low and high period in terms of input clock
|
||||
* periods and check are the result within HW limits between 1 and
|
||||
* 2^32 periods.
|
||||
*/
|
||||
tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, dwc->clk_ns);
|
||||
if (tmp < 1 || tmp > (1ULL << 32))
|
||||
return -ERANGE;
|
||||
low = tmp - 1;
|
||||
|
||||
tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle,
|
||||
dwc->clk_ns);
|
||||
if (tmp < 1 || tmp > (1ULL << 32))
|
||||
return -ERANGE;
|
||||
high = tmp - 1;
|
||||
|
||||
/*
|
||||
* Specification says timer usage flow is to disable timer, then
|
||||
* program it followed by enable. It also says Load Count is loaded
|
||||
* into timer after it is enabled - either after a disable or
|
||||
* a reset. Based on measurements it happens also without disable
|
||||
* whenever Load Count is updated. But follow the specification.
|
||||
*/
|
||||
__dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
|
||||
|
||||
/*
|
||||
* Write Load Count and Load Count 2 registers. Former defines the
|
||||
* width of low period and latter the width of high period in terms
|
||||
* multiple of input clock periods:
|
||||
* Width = ((Count + 1) * input clock period).
|
||||
*/
|
||||
dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm));
|
||||
dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm));
|
||||
|
||||
/*
|
||||
* Set user-defined mode, timer reloads from Load Count registers
|
||||
* when it counts down to 0.
|
||||
* Set PWM mode, it makes output to toggle and width of low and high
|
||||
* periods are set by Load Count registers.
|
||||
*/
|
||||
ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM;
|
||||
dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm));
|
||||
|
||||
/*
|
||||
* Enable timer. Output starts from low period.
|
||||
*/
|
||||
__dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct dwc_pwm *dwc = to_dwc_pwm(chip);
|
||||
|
||||
if (state->polarity != PWM_POLARITY_INVERSED)
|
||||
return -EINVAL;
|
||||
|
||||
if (state->enabled) {
|
||||
if (!pwm->state.enabled)
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
return __dwc_pwm_configure_timer(dwc, pwm, state);
|
||||
} else {
|
||||
if (pwm->state.enabled) {
|
||||
__dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct dwc_pwm *dwc = to_dwc_pwm(chip);
|
||||
u64 duty, period;
|
||||
u32 ctrl, ld, ld2;
|
||||
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
|
||||
ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm->hwpwm));
|
||||
ld = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm));
|
||||
ld2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm));
|
||||
|
||||
state->enabled = !!(ctrl & DWC_TIM_CTRL_EN);
|
||||
|
||||
/*
|
||||
* If we're not in PWM, technically the output is a 50-50
|
||||
* based on the timer load-count only.
|
||||
*/
|
||||
if (ctrl & DWC_TIM_CTRL_PWM) {
|
||||
duty = (ld + 1) * dwc->clk_ns;
|
||||
period = (ld2 + 1) * dwc->clk_ns;
|
||||
period += duty;
|
||||
} else {
|
||||
duty = (ld + 1) * dwc->clk_ns;
|
||||
period = duty * 2;
|
||||
}
|
||||
|
||||
state->polarity = PWM_POLARITY_INVERSED;
|
||||
state->period = period;
|
||||
state->duty_cycle = duty;
|
||||
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwm_ops dwc_pwm_ops = {
|
||||
.apply = dwc_pwm_apply,
|
||||
.get_state = dwc_pwm_get_state,
|
||||
};
|
||||
|
||||
struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
|
||||
{
|
||||
struct dwc_pwm *dwc;
|
||||
|
||||
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
|
||||
if (!dwc)
|
||||
return NULL;
|
||||
|
||||
dwc->clk_ns = 10;
|
||||
dwc->chip.dev = dev;
|
||||
dwc->chip.ops = &dwc_pwm_ops;
|
||||
dwc->chip.npwm = DWC_TIMERS_TOTAL;
|
||||
|
||||
dev_set_drvdata(dev, dwc);
|
||||
return dwc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dwc_pwm_alloc);
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi (Intel)");
|
||||
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
|
||||
MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
|
||||
MODULE_DESCRIPTION("DesignWare PWM Controller");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DesignWare PWM Controller driver
|
||||
* DesignWare PWM Controller driver (PCI part)
|
||||
*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
@ -13,6 +13,8 @@
|
||||
* periods are one or more input clock periods long.
|
||||
*/
|
||||
|
||||
#define DEFAULT_MOUDLE_NAMESPACE dwc_pwm
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -21,198 +23,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pwm.h>
|
||||
|
||||
#define DWC_TIM_LD_CNT(n) ((n) * 0x14)
|
||||
#define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0)
|
||||
#define DWC_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04)
|
||||
#define DWC_TIM_CTRL(n) (((n) * 0x14) + 0x08)
|
||||
#define DWC_TIM_EOI(n) (((n) * 0x14) + 0x0c)
|
||||
#define DWC_TIM_INT_STS(n) (((n) * 0x14) + 0x10)
|
||||
|
||||
#define DWC_TIMERS_INT_STS 0xa0
|
||||
#define DWC_TIMERS_EOI 0xa4
|
||||
#define DWC_TIMERS_RAW_INT_STS 0xa8
|
||||
#define DWC_TIMERS_COMP_VERSION 0xac
|
||||
|
||||
#define DWC_TIMERS_TOTAL 8
|
||||
#define DWC_CLK_PERIOD_NS 10
|
||||
|
||||
/* Timer Control Register */
|
||||
#define DWC_TIM_CTRL_EN BIT(0)
|
||||
#define DWC_TIM_CTRL_MODE BIT(1)
|
||||
#define DWC_TIM_CTRL_MODE_FREE (0 << 1)
|
||||
#define DWC_TIM_CTRL_MODE_USER (1 << 1)
|
||||
#define DWC_TIM_CTRL_INT_MASK BIT(2)
|
||||
#define DWC_TIM_CTRL_PWM BIT(3)
|
||||
|
||||
struct dwc_pwm_ctx {
|
||||
u32 cnt;
|
||||
u32 cnt2;
|
||||
u32 ctrl;
|
||||
};
|
||||
|
||||
struct dwc_pwm {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL];
|
||||
};
|
||||
#define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip))
|
||||
|
||||
static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset)
|
||||
{
|
||||
return readl(dwc->base + offset);
|
||||
}
|
||||
|
||||
static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset)
|
||||
{
|
||||
writel(value, dwc->base + offset);
|
||||
}
|
||||
|
||||
static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm));
|
||||
|
||||
if (enabled)
|
||||
reg |= DWC_TIM_CTRL_EN;
|
||||
else
|
||||
reg &= ~DWC_TIM_CTRL_EN;
|
||||
|
||||
dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm));
|
||||
}
|
||||
|
||||
static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc,
|
||||
struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
u64 tmp;
|
||||
u32 ctrl;
|
||||
u32 high;
|
||||
u32 low;
|
||||
|
||||
/*
|
||||
* Calculate width of low and high period in terms of input clock
|
||||
* periods and check are the result within HW limits between 1 and
|
||||
* 2^32 periods.
|
||||
*/
|
||||
tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, DWC_CLK_PERIOD_NS);
|
||||
if (tmp < 1 || tmp > (1ULL << 32))
|
||||
return -ERANGE;
|
||||
low = tmp - 1;
|
||||
|
||||
tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle,
|
||||
DWC_CLK_PERIOD_NS);
|
||||
if (tmp < 1 || tmp > (1ULL << 32))
|
||||
return -ERANGE;
|
||||
high = tmp - 1;
|
||||
|
||||
/*
|
||||
* Specification says timer usage flow is to disable timer, then
|
||||
* program it followed by enable. It also says Load Count is loaded
|
||||
* into timer after it is enabled - either after a disable or
|
||||
* a reset. Based on measurements it happens also without disable
|
||||
* whenever Load Count is updated. But follow the specification.
|
||||
*/
|
||||
__dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
|
||||
|
||||
/*
|
||||
* Write Load Count and Load Count 2 registers. Former defines the
|
||||
* width of low period and latter the width of high period in terms
|
||||
* multiple of input clock periods:
|
||||
* Width = ((Count + 1) * input clock period).
|
||||
*/
|
||||
dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm));
|
||||
dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm));
|
||||
|
||||
/*
|
||||
* Set user-defined mode, timer reloads from Load Count registers
|
||||
* when it counts down to 0.
|
||||
* Set PWM mode, it makes output to toggle and width of low and high
|
||||
* periods are set by Load Count registers.
|
||||
*/
|
||||
ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM;
|
||||
dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm));
|
||||
|
||||
/*
|
||||
* Enable timer. Output starts from low period.
|
||||
*/
|
||||
__dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct dwc_pwm *dwc = to_dwc_pwm(chip);
|
||||
|
||||
if (state->polarity != PWM_POLARITY_INVERSED)
|
||||
return -EINVAL;
|
||||
|
||||
if (state->enabled) {
|
||||
if (!pwm->state.enabled)
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
return __dwc_pwm_configure_timer(dwc, pwm, state);
|
||||
} else {
|
||||
if (pwm->state.enabled) {
|
||||
__dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct dwc_pwm *dwc = to_dwc_pwm(chip);
|
||||
u64 duty, period;
|
||||
|
||||
pm_runtime_get_sync(chip->dev);
|
||||
|
||||
state->enabled = !!(dwc_pwm_readl(dwc,
|
||||
DWC_TIM_CTRL(pwm->hwpwm)) & DWC_TIM_CTRL_EN);
|
||||
|
||||
duty = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm));
|
||||
duty += 1;
|
||||
duty *= DWC_CLK_PERIOD_NS;
|
||||
state->duty_cycle = duty;
|
||||
|
||||
period = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm));
|
||||
period += 1;
|
||||
period *= DWC_CLK_PERIOD_NS;
|
||||
period += duty;
|
||||
state->period = period;
|
||||
|
||||
state->polarity = PWM_POLARITY_INVERSED;
|
||||
|
||||
pm_runtime_put_sync(chip->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pwm_ops dwc_pwm_ops = {
|
||||
.apply = dwc_pwm_apply,
|
||||
.get_state = dwc_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
|
||||
{
|
||||
struct dwc_pwm *dwc;
|
||||
|
||||
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
|
||||
if (!dwc)
|
||||
return NULL;
|
||||
|
||||
dwc->chip.dev = dev;
|
||||
dwc->chip.ops = &dwc_pwm_ops;
|
||||
dwc->chip.npwm = DWC_TIMERS_TOTAL;
|
||||
|
||||
dev_set_drvdata(dev, dwc);
|
||||
return dwc;
|
||||
}
|
||||
#include "pwm-dwc.h"
|
||||
|
||||
static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
||||
{
|
||||
|
60
drivers/pwm/pwm-dwc.h
Normal file
60
drivers/pwm/pwm-dwc.h
Normal file
@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DesignWare PWM Controller driver
|
||||
*
|
||||
* Copyright (C) 2018-2020 Intel Corporation
|
||||
*
|
||||
* Author: Felipe Balbi (Intel)
|
||||
* Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
* Author: Raymond Tan <raymond.tan@intel.com>
|
||||
*/
|
||||
|
||||
MODULE_IMPORT_NS(dwc_pwm);
|
||||
|
||||
#define DWC_TIM_LD_CNT(n) ((n) * 0x14)
|
||||
#define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0)
|
||||
#define DWC_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04)
|
||||
#define DWC_TIM_CTRL(n) (((n) * 0x14) + 0x08)
|
||||
#define DWC_TIM_EOI(n) (((n) * 0x14) + 0x0c)
|
||||
#define DWC_TIM_INT_STS(n) (((n) * 0x14) + 0x10)
|
||||
|
||||
#define DWC_TIMERS_INT_STS 0xa0
|
||||
#define DWC_TIMERS_EOI 0xa4
|
||||
#define DWC_TIMERS_RAW_INT_STS 0xa8
|
||||
#define DWC_TIMERS_COMP_VERSION 0xac
|
||||
|
||||
#define DWC_TIMERS_TOTAL 8
|
||||
|
||||
/* Timer Control Register */
|
||||
#define DWC_TIM_CTRL_EN BIT(0)
|
||||
#define DWC_TIM_CTRL_MODE BIT(1)
|
||||
#define DWC_TIM_CTRL_MODE_FREE (0 << 1)
|
||||
#define DWC_TIM_CTRL_MODE_USER (1 << 1)
|
||||
#define DWC_TIM_CTRL_INT_MASK BIT(2)
|
||||
#define DWC_TIM_CTRL_PWM BIT(3)
|
||||
|
||||
struct dwc_pwm_ctx {
|
||||
u32 cnt;
|
||||
u32 cnt2;
|
||||
u32 ctrl;
|
||||
};
|
||||
|
||||
struct dwc_pwm {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
unsigned int clk_ns;
|
||||
struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL];
|
||||
};
|
||||
#define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip))
|
||||
|
||||
static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset)
|
||||
{
|
||||
return readl(dwc->base + offset);
|
||||
}
|
||||
|
||||
static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset)
|
||||
{
|
||||
writel(value, dwc->base + offset);
|
||||
}
|
||||
|
||||
extern struct dwc_pwm *dwc_pwm_alloc(struct device *dev);
|
@ -159,7 +159,6 @@ static const struct pwm_ops ep93xx_pwm_ops = {
|
||||
.request = ep93xx_pwm_request,
|
||||
.free = ep93xx_pwm_free,
|
||||
.apply = ep93xx_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ep93xx_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -350,7 +350,6 @@ static const struct pwm_ops fsl_pwm_ops = {
|
||||
.request = fsl_pwm_request,
|
||||
.free = fsl_pwm_free,
|
||||
.apply = fsl_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
|
||||
|
@ -185,7 +185,6 @@ static const struct pwm_ops hibvt_pwm_ops = {
|
||||
.get_state = hibvt_pwm_get_state,
|
||||
.apply = hibvt_pwm_apply,
|
||||
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int hibvt_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -208,7 +208,6 @@ static int img_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops img_pwm_ops = {
|
||||
.apply = img_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct img_pwm_soc_data pistachio_pwm = {
|
||||
|
@ -332,7 +332,6 @@ static const struct pwm_ops imx_tpm_pwm_ops = {
|
||||
.free = pwm_imx_tpm_free,
|
||||
.get_state = pwm_imx_tpm_get_state,
|
||||
.apply = pwm_imx_tpm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int pwm_imx_tpm_probe(struct platform_device *pdev)
|
||||
@ -351,18 +350,11 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(tpm->base))
|
||||
return PTR_ERR(tpm->base);
|
||||
|
||||
tpm->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
tpm->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(tpm->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(tpm->clk),
|
||||
"failed to get PWM clock\n");
|
||||
|
||||
ret = clk_prepare_enable(tpm->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to prepare or enable clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tpm->chip.dev = &pdev->dev;
|
||||
tpm->chip.ops = &imx_tpm_pwm_ops;
|
||||
|
||||
@ -372,22 +364,11 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
|
||||
|
||||
mutex_init(&tpm->lock);
|
||||
|
||||
ret = pwmchip_add(&tpm->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
clk_disable_unprepare(tpm->clk);
|
||||
}
|
||||
ret = devm_pwmchip_add(&pdev->dev, &tpm->chip);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pwm_imx_tpm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_tpm_pwm_chip *tpm = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&tpm->chip);
|
||||
|
||||
clk_disable_unprepare(tpm->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev)
|
||||
@ -437,7 +418,6 @@ static struct platform_driver imx_tpm_pwm_driver = {
|
||||
.pm = &imx_tpm_pwm_pm,
|
||||
},
|
||||
.probe = pwm_imx_tpm_probe,
|
||||
.remove_new = pwm_imx_tpm_remove,
|
||||
};
|
||||
module_platform_driver(imx_tpm_pwm_driver);
|
||||
|
||||
|
@ -146,7 +146,6 @@ static int pwm_imx1_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops pwm_imx1_ops = {
|
||||
.apply = pwm_imx1_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id pwm_imx1_dt_ids[] = {
|
||||
|
@ -296,7 +296,6 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops pwm_imx27_ops = {
|
||||
.apply = pwm_imx27_apply,
|
||||
.get_state = pwm_imx27_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id pwm_imx27_dt_ids[] = {
|
||||
|
@ -107,7 +107,6 @@ static int lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops lgm_pwm_ops = {
|
||||
.get_state = lgm_pwm_get_state,
|
||||
.apply = lgm_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void lgm_pwm_init(struct lgm_pwm_chip *pc)
|
||||
|
@ -166,7 +166,6 @@ static int iqs620_pwm_notifier(struct notifier_block *notifier,
|
||||
static const struct pwm_ops iqs620_pwm_ops = {
|
||||
.apply = iqs620_pwm_apply,
|
||||
.get_state = iqs620_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void iqs620_pwm_notifier_unregister(void *context)
|
||||
|
@ -27,6 +27,7 @@ struct soc_info {
|
||||
struct jz4740_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct regmap *map;
|
||||
struct clk *clk[];
|
||||
};
|
||||
|
||||
static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
|
||||
@ -70,14 +71,15 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
return err;
|
||||
}
|
||||
|
||||
pwm_set_chip_data(pwm, clk);
|
||||
jz->clk[pwm->hwpwm] = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct clk *clk = pwm_get_chip_data(pwm);
|
||||
struct jz4740_pwm_chip *jz = to_jz4740(chip);
|
||||
struct clk *clk = jz->clk[pwm->hwpwm];
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
clk_put(clk);
|
||||
@ -121,9 +123,9 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
|
||||
struct jz4740_pwm_chip *jz = to_jz4740(pwm->chip);
|
||||
unsigned long long tmp = 0xffffull * NSEC_PER_SEC;
|
||||
struct clk *clk = pwm_get_chip_data(pwm);
|
||||
struct clk *clk = jz->clk[pwm->hwpwm];
|
||||
unsigned long period, duty;
|
||||
long rate;
|
||||
int err;
|
||||
@ -173,16 +175,16 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
/* Reset counter to 0 */
|
||||
regmap_write(jz4740->map, TCU_REG_TCNTc(pwm->hwpwm), 0);
|
||||
regmap_write(jz->map, TCU_REG_TCNTc(pwm->hwpwm), 0);
|
||||
|
||||
/* Set duty */
|
||||
regmap_write(jz4740->map, TCU_REG_TDHRc(pwm->hwpwm), duty);
|
||||
regmap_write(jz->map, TCU_REG_TDHRc(pwm->hwpwm), duty);
|
||||
|
||||
/* Set period */
|
||||
regmap_write(jz4740->map, TCU_REG_TDFRc(pwm->hwpwm), period);
|
||||
regmap_write(jz->map, TCU_REG_TDFRc(pwm->hwpwm), period);
|
||||
|
||||
/* Set abrupt shutdown */
|
||||
regmap_set_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
|
||||
regmap_set_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
|
||||
TCU_TCSR_PWM_SD);
|
||||
|
||||
/*
|
||||
@ -199,10 +201,10 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
* state instead of its inactive state.
|
||||
*/
|
||||
if ((state->polarity == PWM_POLARITY_NORMAL) ^ state->enabled)
|
||||
regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
|
||||
regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
|
||||
TCU_TCSR_PWM_INITL_HIGH, 0);
|
||||
else
|
||||
regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
|
||||
regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm),
|
||||
TCU_TCSR_PWM_INITL_HIGH,
|
||||
TCU_TCSR_PWM_INITL_HIGH);
|
||||
|
||||
@ -216,34 +218,34 @@ static const struct pwm_ops jz4740_pwm_ops = {
|
||||
.request = jz4740_pwm_request,
|
||||
.free = jz4740_pwm_free,
|
||||
.apply = jz4740_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int jz4740_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct jz4740_pwm_chip *jz4740;
|
||||
struct jz4740_pwm_chip *jz;
|
||||
const struct soc_info *info;
|
||||
|
||||
info = device_get_match_data(dev);
|
||||
if (!info)
|
||||
return -EINVAL;
|
||||
|
||||
jz4740 = devm_kzalloc(dev, sizeof(*jz4740), GFP_KERNEL);
|
||||
if (!jz4740)
|
||||
jz = devm_kzalloc(dev, struct_size(jz, clk, info->num_pwms),
|
||||
GFP_KERNEL);
|
||||
if (!jz)
|
||||
return -ENOMEM;
|
||||
|
||||
jz4740->map = device_node_to_regmap(dev->parent->of_node);
|
||||
if (IS_ERR(jz4740->map)) {
|
||||
dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz4740->map));
|
||||
return PTR_ERR(jz4740->map);
|
||||
jz->map = device_node_to_regmap(dev->parent->of_node);
|
||||
if (IS_ERR(jz->map)) {
|
||||
dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz->map));
|
||||
return PTR_ERR(jz->map);
|
||||
}
|
||||
|
||||
jz4740->chip.dev = dev;
|
||||
jz4740->chip.ops = &jz4740_pwm_ops;
|
||||
jz4740->chip.npwm = info->num_pwms;
|
||||
jz->chip.dev = dev;
|
||||
jz->chip.ops = &jz4740_pwm_ops;
|
||||
jz->chip.npwm = info->num_pwms;
|
||||
|
||||
return devm_pwmchip_add(dev, &jz4740->chip);
|
||||
return devm_pwmchip_add(dev, &jz->chip);
|
||||
}
|
||||
|
||||
static const struct soc_info jz4740_soc_info = {
|
||||
|
@ -178,7 +178,6 @@ static int keembay_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
static const struct pwm_ops keembay_pwm_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.apply = keembay_pwm_apply,
|
||||
.get_state = keembay_pwm_get_state,
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ struct lp3943_pwm {
|
||||
struct pwm_chip chip;
|
||||
struct lp3943 *lp3943;
|
||||
struct lp3943_platform_data *pdata;
|
||||
struct lp3943_pwm_map pwm_map[LP3943_NUM_PWMS];
|
||||
};
|
||||
|
||||
static inline struct lp3943_pwm *to_lp3943_pwm(struct pwm_chip *chip)
|
||||
@ -35,13 +36,9 @@ lp3943_pwm_request_map(struct lp3943_pwm *lp3943_pwm, int hwpwm)
|
||||
{
|
||||
struct lp3943_platform_data *pdata = lp3943_pwm->pdata;
|
||||
struct lp3943 *lp3943 = lp3943_pwm->lp3943;
|
||||
struct lp3943_pwm_map *pwm_map;
|
||||
struct lp3943_pwm_map *pwm_map = &lp3943_pwm->pwm_map[hwpwm];
|
||||
int i, offset;
|
||||
|
||||
pwm_map = kzalloc(sizeof(*pwm_map), GFP_KERNEL);
|
||||
if (!pwm_map)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pwm_map->output = pdata->pwms[hwpwm]->output;
|
||||
pwm_map->num_outputs = pdata->pwms[hwpwm]->num_outputs;
|
||||
|
||||
@ -49,10 +46,8 @@ lp3943_pwm_request_map(struct lp3943_pwm *lp3943_pwm, int hwpwm)
|
||||
offset = pwm_map->output[i];
|
||||
|
||||
/* Return an error if the pin is already assigned */
|
||||
if (test_and_set_bit(offset, &lp3943->pin_used)) {
|
||||
kfree(pwm_map);
|
||||
if (test_and_set_bit(offset, &lp3943->pin_used))
|
||||
return ERR_PTR(-EBUSY);
|
||||
}
|
||||
}
|
||||
|
||||
return pwm_map;
|
||||
@ -67,7 +62,7 @@ static int lp3943_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
if (IS_ERR(pwm_map))
|
||||
return PTR_ERR(pwm_map);
|
||||
|
||||
return pwm_set_chip_data(pwm, pwm_map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lp3943_pwm_free_map(struct lp3943_pwm *lp3943_pwm,
|
||||
@ -80,14 +75,12 @@ static void lp3943_pwm_free_map(struct lp3943_pwm *lp3943_pwm,
|
||||
offset = pwm_map->output[i];
|
||||
clear_bit(offset, &lp3943->pin_used);
|
||||
}
|
||||
|
||||
kfree(pwm_map);
|
||||
}
|
||||
|
||||
static void lp3943_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct lp3943_pwm *lp3943_pwm = to_lp3943_pwm(chip);
|
||||
struct lp3943_pwm_map *pwm_map = pwm_get_chip_data(pwm);
|
||||
struct lp3943_pwm_map *pwm_map = &lp3943_pwm->pwm_map[pwm->hwpwm];
|
||||
|
||||
lp3943_pwm_free_map(lp3943_pwm, pwm_map);
|
||||
}
|
||||
@ -159,7 +152,7 @@ static int lp3943_pwm_set_mode(struct lp3943_pwm *lp3943_pwm,
|
||||
static int lp3943_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct lp3943_pwm *lp3943_pwm = to_lp3943_pwm(chip);
|
||||
struct lp3943_pwm_map *pwm_map = pwm_get_chip_data(pwm);
|
||||
struct lp3943_pwm_map *pwm_map = &lp3943_pwm->pwm_map[pwm->hwpwm];
|
||||
u8 val;
|
||||
|
||||
if (pwm->hwpwm == 0)
|
||||
@ -178,7 +171,7 @@ static int lp3943_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
static void lp3943_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct lp3943_pwm *lp3943_pwm = to_lp3943_pwm(chip);
|
||||
struct lp3943_pwm_map *pwm_map = pwm_get_chip_data(pwm);
|
||||
struct lp3943_pwm_map *pwm_map = &lp3943_pwm->pwm_map[pwm->hwpwm];
|
||||
|
||||
/*
|
||||
* LP3943 outputs are open-drain, so the pin should be configured
|
||||
@ -216,7 +209,6 @@ static const struct pwm_ops lp3943_pwm_ops = {
|
||||
.request = lp3943_pwm_request,
|
||||
.free = lp3943_pwm_free,
|
||||
.apply = lp3943_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int lp3943_pwm_parse_dt(struct device *dev,
|
||||
|
@ -341,7 +341,6 @@ static const struct pwm_ops lpc18xx_pwm_ops = {
|
||||
.apply = lpc18xx_pwm_apply,
|
||||
.request = lpc18xx_pwm_request,
|
||||
.free = lpc18xx_pwm_free,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id lpc18xx_pwm_of_match[] = {
|
||||
|
@ -115,7 +115,6 @@ static int lpc32xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops lpc32xx_pwm_ops = {
|
||||
.apply = lpc32xx_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int lpc32xx_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -243,7 +243,6 @@ static int pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops pwm_lpss_ops = {
|
||||
.apply = pwm_lpss_apply,
|
||||
.get_state = pwm_lpss_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
|
||||
|
@ -229,7 +229,6 @@ static int pwm_mediatek_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops pwm_mediatek_ops = {
|
||||
.apply = pwm_mediatek_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int pwm_mediatek_probe(struct platform_device *pdev)
|
||||
|
@ -335,7 +335,6 @@ static const struct pwm_ops meson_pwm_ops = {
|
||||
.free = meson_pwm_free,
|
||||
.apply = meson_pwm_apply,
|
||||
.get_state = meson_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const char * const pwm_meson8b_parent_names[] = {
|
||||
|
@ -435,7 +435,6 @@ static int mchp_core_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm
|
||||
static const struct pwm_ops mchp_core_pwm_ops = {
|
||||
.apply = mchp_core_pwm_apply,
|
||||
.get_state = mchp_core_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id mchp_core_of_match[] = {
|
||||
|
@ -227,7 +227,6 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
|
||||
static const struct pwm_ops mtk_disp_pwm_ops = {
|
||||
.apply = mtk_disp_pwm_apply,
|
||||
.get_state = mtk_disp_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int mtk_disp_pwm_probe(struct platform_device *pdev)
|
||||
@ -247,34 +246,25 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
mdp->clk_main = devm_clk_get(&pdev->dev, "main");
|
||||
if (IS_ERR(mdp->clk_main))
|
||||
return PTR_ERR(mdp->clk_main);
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(mdp->clk_main),
|
||||
"Failed to get main clock\n");
|
||||
|
||||
mdp->clk_mm = devm_clk_get(&pdev->dev, "mm");
|
||||
if (IS_ERR(mdp->clk_mm))
|
||||
return PTR_ERR(mdp->clk_mm);
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(mdp->clk_mm),
|
||||
"Failed to get mm clock\n");
|
||||
|
||||
mdp->chip.dev = &pdev->dev;
|
||||
mdp->chip.ops = &mtk_disp_pwm_ops;
|
||||
mdp->chip.npwm = 1;
|
||||
|
||||
ret = pwmchip_add(&mdp->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %pe\n", ERR_PTR(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, mdp);
|
||||
ret = devm_pwmchip_add(&pdev->dev, &mdp->chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mtk_disp_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mtk_disp_pwm *mdp = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&mdp->chip);
|
||||
}
|
||||
|
||||
static const struct mtk_pwm_data mt2701_pwm_data = {
|
||||
.enable_mask = BIT(16),
|
||||
.con0 = 0xa8,
|
||||
@ -320,7 +310,6 @@ static struct platform_driver mtk_disp_pwm_driver = {
|
||||
.of_match_table = mtk_disp_pwm_of_match,
|
||||
},
|
||||
.probe = mtk_disp_pwm_probe,
|
||||
.remove_new = mtk_disp_pwm_remove,
|
||||
};
|
||||
module_platform_driver(mtk_disp_pwm_driver);
|
||||
|
||||
|
@ -115,7 +115,6 @@ static int mxs_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops mxs_pwm_ops = {
|
||||
.apply = mxs_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int mxs_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -126,7 +126,6 @@ static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev,
|
||||
}
|
||||
|
||||
static const struct pwm_ops ntxec_pwm_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.apply = ntxec_pwm_apply,
|
||||
/*
|
||||
* No .get_state callback, because the current state cannot be read
|
||||
|
@ -311,7 +311,6 @@ static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
|
||||
|
||||
static const struct pwm_ops pwm_omap_dmtimer_ops = {
|
||||
.apply = pwm_omap_dmtimer_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
|
||||
@ -466,7 +465,7 @@ MODULE_DEVICE_TABLE(of, pwm_omap_dmtimer_of_match);
|
||||
static struct platform_driver pwm_omap_dmtimer_driver = {
|
||||
.driver = {
|
||||
.name = "omap-dmtimer-pwm",
|
||||
.of_match_table = of_match_ptr(pwm_omap_dmtimer_of_match),
|
||||
.of_match_table = pwm_omap_dmtimer_of_match,
|
||||
},
|
||||
.probe = pwm_omap_dmtimer_probe,
|
||||
.remove_new = pwm_omap_dmtimer_remove,
|
||||
|
@ -505,7 +505,6 @@ static const struct pwm_ops pca9685_pwm_ops = {
|
||||
.get_state = pca9685_pwm_get_state,
|
||||
.request = pca9685_pwm_request,
|
||||
.free = pca9685_pwm_free,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct regmap_config pca9685_regmap_i2c_config = {
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
@ -135,7 +135,6 @@ static int pxa_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops pxa_pwm_ops = {
|
||||
.apply = pxa_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
@ -135,7 +135,6 @@ static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops raspberrypi_pwm_ops = {
|
||||
.get_state = raspberrypi_pwm_get_state,
|
||||
.apply = raspberrypi_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int raspberrypi_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -198,7 +198,6 @@ static const struct pwm_ops rcar_pwm_ops = {
|
||||
.request = rcar_pwm_request,
|
||||
.free = rcar_pwm_free,
|
||||
.apply = rcar_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int rcar_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -85,6 +85,7 @@ struct tpu_device {
|
||||
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
struct tpu_pwm_device tpd[TPU_CHANNEL_MAX];
|
||||
};
|
||||
|
||||
#define to_tpu_device(c) container_of(c, struct tpu_device, chip)
|
||||
@ -215,9 +216,7 @@ static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
if (pwm->hwpwm >= TPU_CHANNEL_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
tpd = kzalloc(sizeof(*tpd), GFP_KERNEL);
|
||||
if (tpd == NULL)
|
||||
return -ENOMEM;
|
||||
tpd = &tpu->tpd[pwm->hwpwm];
|
||||
|
||||
tpd->tpu = tpu;
|
||||
tpd->channel = pwm->hwpwm;
|
||||
@ -228,24 +227,22 @@ static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
tpd->timer_on = false;
|
||||
|
||||
pwm_set_chip_data(pwm, tpd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm);
|
||||
struct tpu_device *tpu = to_tpu_device(chip);
|
||||
struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm];
|
||||
|
||||
tpu_pwm_timer_stop(tpd);
|
||||
kfree(tpd);
|
||||
}
|
||||
|
||||
static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
u64 duty_ns, u64 period_ns, bool enabled)
|
||||
{
|
||||
struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm);
|
||||
struct tpu_device *tpu = to_tpu_device(chip);
|
||||
struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm];
|
||||
unsigned int prescaler;
|
||||
bool duty_only = false;
|
||||
u32 clk_rate;
|
||||
@ -353,7 +350,8 @@ static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static int tpu_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
enum pwm_polarity polarity)
|
||||
{
|
||||
struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm);
|
||||
struct tpu_device *tpu = to_tpu_device(chip);
|
||||
struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm];
|
||||
|
||||
tpd->polarity = polarity;
|
||||
|
||||
@ -362,7 +360,8 @@ static int tpu_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static int tpu_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm);
|
||||
struct tpu_device *tpu = to_tpu_device(chip);
|
||||
struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm];
|
||||
int ret;
|
||||
|
||||
ret = tpu_pwm_timer_start(tpd);
|
||||
@ -384,7 +383,8 @@ static int tpu_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
||||
static void tpu_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct tpu_pwm_device *tpd = pwm_get_chip_data(pwm);
|
||||
struct tpu_device *tpu = to_tpu_device(chip);
|
||||
struct tpu_pwm_device *tpd = &tpu->tpd[pwm->hwpwm];
|
||||
|
||||
/* The timer must be running to modify the pin output configuration. */
|
||||
tpu_pwm_timer_start(tpd);
|
||||
@ -431,7 +431,6 @@ static const struct pwm_ops tpu_pwm_ops = {
|
||||
.request = tpu_pwm_request,
|
||||
.free = tpu_pwm_free,
|
||||
.apply = tpu_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -228,7 +228,6 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops rockchip_pwm_ops = {
|
||||
.get_state = rockchip_pwm_get_state,
|
||||
.apply = rockchip_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct rockchip_pwm_data pwm_data_v1 = {
|
||||
|
@ -438,7 +438,6 @@ static const struct pwm_ops rz_mtu3_pwm_ops = {
|
||||
.free = rz_mtu3_pwm_free,
|
||||
.get_state = rz_mtu3_pwm_get_state,
|
||||
.apply = rz_mtu3_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int rz_mtu3_pwm_pm_runtime_suspend(struct device *dev)
|
||||
|
@ -77,6 +77,7 @@ struct samsung_pwm_channel {
|
||||
* @base_clk: base clock used to drive the timers
|
||||
* @tclk0: external clock 0 (can be ERR_PTR if not present)
|
||||
* @tclk1: external clock 1 (can be ERR_PTR if not present)
|
||||
* @channel: per channel driver data
|
||||
*/
|
||||
struct samsung_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
@ -88,6 +89,7 @@ struct samsung_pwm_chip {
|
||||
struct clk *base_clk;
|
||||
struct clk *tclk0;
|
||||
struct clk *tclk1;
|
||||
struct samsung_pwm_channel channel[SAMSUNG_PWM_NUM];
|
||||
};
|
||||
|
||||
#ifndef CONFIG_CLKSRC_SAMSUNG_PWM
|
||||
@ -117,21 +119,21 @@ static inline unsigned int to_tcon_channel(unsigned int channel)
|
||||
return (channel == 0) ? 0 : (channel + 1);
|
||||
}
|
||||
|
||||
static void __pwm_samsung_manual_update(struct samsung_pwm_chip *chip,
|
||||
static void __pwm_samsung_manual_update(struct samsung_pwm_chip *our_chip,
|
||||
struct pwm_device *pwm)
|
||||
{
|
||||
unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm);
|
||||
u32 tcon;
|
||||
|
||||
tcon = readl(chip->base + REG_TCON);
|
||||
tcon = readl(our_chip->base + REG_TCON);
|
||||
tcon |= TCON_MANUALUPDATE(tcon_chan);
|
||||
writel(tcon, chip->base + REG_TCON);
|
||||
writel(tcon, our_chip->base + REG_TCON);
|
||||
|
||||
tcon &= ~TCON_MANUALUPDATE(tcon_chan);
|
||||
writel(tcon, chip->base + REG_TCON);
|
||||
writel(tcon, our_chip->base + REG_TCON);
|
||||
}
|
||||
|
||||
static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
|
||||
static void pwm_samsung_set_divisor(struct samsung_pwm_chip *our_chip,
|
||||
unsigned int channel, u8 divisor)
|
||||
{
|
||||
u8 shift = TCFG1_SHIFT(channel);
|
||||
@ -139,39 +141,39 @@ static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
|
||||
u32 reg;
|
||||
u8 bits;
|
||||
|
||||
bits = (fls(divisor) - 1) - pwm->variant.div_base;
|
||||
bits = (fls(divisor) - 1) - our_chip->variant.div_base;
|
||||
|
||||
spin_lock_irqsave(&samsung_pwm_lock, flags);
|
||||
|
||||
reg = readl(pwm->base + REG_TCFG1);
|
||||
reg = readl(our_chip->base + REG_TCFG1);
|
||||
reg &= ~(TCFG1_MUX_MASK << shift);
|
||||
reg |= bits << shift;
|
||||
writel(reg, pwm->base + REG_TCFG1);
|
||||
writel(reg, our_chip->base + REG_TCFG1);
|
||||
|
||||
spin_unlock_irqrestore(&samsung_pwm_lock, flags);
|
||||
}
|
||||
|
||||
static int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip, unsigned int chan)
|
||||
static int pwm_samsung_is_tdiv(struct samsung_pwm_chip *our_chip, unsigned int chan)
|
||||
{
|
||||
struct samsung_pwm_variant *variant = &chip->variant;
|
||||
struct samsung_pwm_variant *variant = &our_chip->variant;
|
||||
u32 reg;
|
||||
|
||||
reg = readl(chip->base + REG_TCFG1);
|
||||
reg = readl(our_chip->base + REG_TCFG1);
|
||||
reg >>= TCFG1_SHIFT(chan);
|
||||
reg &= TCFG1_MUX_MASK;
|
||||
|
||||
return (BIT(reg) & variant->tclk_mask) == 0;
|
||||
}
|
||||
|
||||
static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *chip,
|
||||
static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *our_chip,
|
||||
unsigned int chan)
|
||||
{
|
||||
unsigned long rate;
|
||||
u32 reg;
|
||||
|
||||
rate = clk_get_rate(chip->base_clk);
|
||||
rate = clk_get_rate(our_chip->base_clk);
|
||||
|
||||
reg = readl(chip->base + REG_TCFG0);
|
||||
reg = readl(our_chip->base + REG_TCFG0);
|
||||
if (chan >= 2)
|
||||
reg >>= TCFG0_PRESCALER1_SHIFT;
|
||||
reg &= TCFG0_PRESCALER_MASK;
|
||||
@ -179,28 +181,28 @@ static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *chip,
|
||||
return rate / (reg + 1);
|
||||
}
|
||||
|
||||
static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip,
|
||||
static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *our_chip,
|
||||
unsigned int chan, unsigned long freq)
|
||||
{
|
||||
struct samsung_pwm_variant *variant = &chip->variant;
|
||||
struct samsung_pwm_variant *variant = &our_chip->variant;
|
||||
unsigned long rate;
|
||||
struct clk *clk;
|
||||
u8 div;
|
||||
|
||||
if (!pwm_samsung_is_tdiv(chip, chan)) {
|
||||
clk = (chan < 2) ? chip->tclk0 : chip->tclk1;
|
||||
if (!pwm_samsung_is_tdiv(our_chip, chan)) {
|
||||
clk = (chan < 2) ? our_chip->tclk0 : our_chip->tclk1;
|
||||
if (!IS_ERR(clk)) {
|
||||
rate = clk_get_rate(clk);
|
||||
if (rate)
|
||||
return rate;
|
||||
}
|
||||
|
||||
dev_warn(chip->chip.dev,
|
||||
dev_warn(our_chip->chip.dev,
|
||||
"tclk of PWM %d is inoperational, using tdiv\n", chan);
|
||||
}
|
||||
|
||||
rate = pwm_samsung_get_tin_rate(chip, chan);
|
||||
dev_dbg(chip->chip.dev, "tin parent at %lu\n", rate);
|
||||
rate = pwm_samsung_get_tin_rate(our_chip, chan);
|
||||
dev_dbg(our_chip->chip.dev, "tin parent at %lu\n", rate);
|
||||
|
||||
/*
|
||||
* Compare minimum PWM frequency that can be achieved with possible
|
||||
@ -220,7 +222,7 @@ static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip,
|
||||
div = variant->div_base;
|
||||
}
|
||||
|
||||
pwm_samsung_set_divisor(chip, chan, BIT(div));
|
||||
pwm_samsung_set_divisor(our_chip, chan, BIT(div));
|
||||
|
||||
return rate >> div;
|
||||
}
|
||||
@ -228,7 +230,6 @@ static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip,
|
||||
static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
|
||||
struct samsung_pwm_channel *our_chan;
|
||||
|
||||
if (!(our_chip->variant.output_mask & BIT(pwm->hwpwm))) {
|
||||
dev_warn(chip->dev,
|
||||
@ -237,20 +238,11 @@ static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
our_chan = kzalloc(sizeof(*our_chan), GFP_KERNEL);
|
||||
if (!our_chan)
|
||||
return -ENOMEM;
|
||||
|
||||
pwm_set_chip_data(pwm, our_chan);
|
||||
memset(&our_chip->channel[pwm->hwpwm], 0, sizeof(our_chip->channel[pwm->hwpwm]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pwm_samsung_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
kfree(pwm_get_chip_data(pwm));
|
||||
}
|
||||
|
||||
static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
|
||||
@ -302,14 +294,14 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
spin_unlock_irqrestore(&samsung_pwm_lock, flags);
|
||||
}
|
||||
|
||||
static void pwm_samsung_manual_update(struct samsung_pwm_chip *chip,
|
||||
static void pwm_samsung_manual_update(struct samsung_pwm_chip *our_chip,
|
||||
struct pwm_device *pwm)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&samsung_pwm_lock, flags);
|
||||
|
||||
__pwm_samsung_manual_update(chip, pwm);
|
||||
__pwm_samsung_manual_update(our_chip, pwm);
|
||||
|
||||
spin_unlock_irqrestore(&samsung_pwm_lock, flags);
|
||||
}
|
||||
@ -318,7 +310,7 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns, bool force_period)
|
||||
{
|
||||
struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
|
||||
struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm);
|
||||
struct samsung_pwm_channel *chan = &our_chip->channel[pwm->hwpwm];
|
||||
u32 tin_ns = chan->tin_ns, tcnt, tcmp, oldtcmp;
|
||||
|
||||
tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm));
|
||||
@ -393,7 +385,7 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
return __pwm_samsung_config(chip, pwm, duty_ns, period_ns, false);
|
||||
}
|
||||
|
||||
static void pwm_samsung_set_invert(struct samsung_pwm_chip *chip,
|
||||
static void pwm_samsung_set_invert(struct samsung_pwm_chip *our_chip,
|
||||
unsigned int channel, bool invert)
|
||||
{
|
||||
unsigned int tcon_chan = to_tcon_channel(channel);
|
||||
@ -402,17 +394,17 @@ static void pwm_samsung_set_invert(struct samsung_pwm_chip *chip,
|
||||
|
||||
spin_lock_irqsave(&samsung_pwm_lock, flags);
|
||||
|
||||
tcon = readl(chip->base + REG_TCON);
|
||||
tcon = readl(our_chip->base + REG_TCON);
|
||||
|
||||
if (invert) {
|
||||
chip->inverter_mask |= BIT(channel);
|
||||
our_chip->inverter_mask |= BIT(channel);
|
||||
tcon |= TCON_INVERT(tcon_chan);
|
||||
} else {
|
||||
chip->inverter_mask &= ~BIT(channel);
|
||||
our_chip->inverter_mask &= ~BIT(channel);
|
||||
tcon &= ~TCON_INVERT(tcon_chan);
|
||||
}
|
||||
|
||||
writel(tcon, chip->base + REG_TCON);
|
||||
writel(tcon, our_chip->base + REG_TCON);
|
||||
|
||||
spin_unlock_irqrestore(&samsung_pwm_lock, flags);
|
||||
}
|
||||
@ -473,9 +465,7 @@ static int pwm_samsung_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops pwm_samsung_ops = {
|
||||
.request = pwm_samsung_request,
|
||||
.free = pwm_samsung_free,
|
||||
.apply = pwm_samsung_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
@ -517,9 +507,9 @@ static const struct of_device_id samsung_pwm_matches[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, samsung_pwm_matches);
|
||||
|
||||
static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
|
||||
static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
|
||||
{
|
||||
struct device_node *np = chip->chip.dev->of_node;
|
||||
struct device_node *np = our_chip->chip.dev->of_node;
|
||||
const struct of_device_id *match;
|
||||
struct property *prop;
|
||||
const __be32 *cur;
|
||||
@ -529,22 +519,22 @@ static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
memcpy(&chip->variant, match->data, sizeof(chip->variant));
|
||||
memcpy(&our_chip->variant, match->data, sizeof(our_chip->variant));
|
||||
|
||||
of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) {
|
||||
if (val >= SAMSUNG_PWM_NUM) {
|
||||
dev_err(chip->chip.dev,
|
||||
dev_err(our_chip->chip.dev,
|
||||
"%s: invalid channel index in samsung,pwm-outputs property\n",
|
||||
__func__);
|
||||
continue;
|
||||
}
|
||||
chip->variant.output_mask |= BIT(val);
|
||||
our_chip->variant.output_mask |= BIT(val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
|
||||
static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -553,21 +543,21 @@ static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
|
||||
static int pwm_samsung_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct samsung_pwm_chip *chip;
|
||||
struct samsung_pwm_chip *our_chip;
|
||||
unsigned int chan;
|
||||
int ret;
|
||||
|
||||
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (chip == NULL)
|
||||
our_chip = devm_kzalloc(&pdev->dev, sizeof(*our_chip), GFP_KERNEL);
|
||||
if (our_chip == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->chip.dev = &pdev->dev;
|
||||
chip->chip.ops = &pwm_samsung_ops;
|
||||
chip->chip.npwm = SAMSUNG_PWM_NUM;
|
||||
chip->inverter_mask = BIT(SAMSUNG_PWM_NUM) - 1;
|
||||
our_chip->chip.dev = &pdev->dev;
|
||||
our_chip->chip.ops = &pwm_samsung_ops;
|
||||
our_chip->chip.npwm = SAMSUNG_PWM_NUM;
|
||||
our_chip->inverter_mask = BIT(SAMSUNG_PWM_NUM) - 1;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
|
||||
ret = pwm_samsung_parse_dt(chip);
|
||||
ret = pwm_samsung_parse_dt(our_chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
@ -576,58 +566,58 @@ static int pwm_samsung_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&chip->variant, pdev->dev.platform_data,
|
||||
sizeof(chip->variant));
|
||||
memcpy(&our_chip->variant, pdev->dev.platform_data,
|
||||
sizeof(our_chip->variant));
|
||||
}
|
||||
|
||||
chip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(chip->base))
|
||||
return PTR_ERR(chip->base);
|
||||
our_chip->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(our_chip->base))
|
||||
return PTR_ERR(our_chip->base);
|
||||
|
||||
chip->base_clk = devm_clk_get(&pdev->dev, "timers");
|
||||
if (IS_ERR(chip->base_clk)) {
|
||||
our_chip->base_clk = devm_clk_get(&pdev->dev, "timers");
|
||||
if (IS_ERR(our_chip->base_clk)) {
|
||||
dev_err(dev, "failed to get timer base clk\n");
|
||||
return PTR_ERR(chip->base_clk);
|
||||
return PTR_ERR(our_chip->base_clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(chip->base_clk);
|
||||
ret = clk_prepare_enable(our_chip->base_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable base clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (chan = 0; chan < SAMSUNG_PWM_NUM; ++chan)
|
||||
if (chip->variant.output_mask & BIT(chan))
|
||||
pwm_samsung_set_invert(chip, chan, true);
|
||||
if (our_chip->variant.output_mask & BIT(chan))
|
||||
pwm_samsung_set_invert(our_chip, chan, true);
|
||||
|
||||
/* Following clocks are optional. */
|
||||
chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0");
|
||||
chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1");
|
||||
our_chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0");
|
||||
our_chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1");
|
||||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
platform_set_drvdata(pdev, our_chip);
|
||||
|
||||
ret = pwmchip_add(&chip->chip);
|
||||
ret = pwmchip_add(&our_chip->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register PWM chip\n");
|
||||
clk_disable_unprepare(chip->base_clk);
|
||||
clk_disable_unprepare(our_chip->base_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
|
||||
clk_get_rate(chip->base_clk),
|
||||
!IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
|
||||
!IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
|
||||
clk_get_rate(our_chip->base_clk),
|
||||
!IS_ERR(our_chip->tclk0) ? clk_get_rate(our_chip->tclk0) : 0,
|
||||
!IS_ERR(our_chip->tclk1) ? clk_get_rate(our_chip->tclk1) : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pwm_samsung_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct samsung_pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
struct samsung_pwm_chip *our_chip = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&chip->chip);
|
||||
pwmchip_remove(&our_chip->chip);
|
||||
|
||||
clk_disable_unprepare(chip->base_clk);
|
||||
clk_disable_unprepare(our_chip->base_clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -639,9 +629,9 @@ static int pwm_samsung_resume(struct device *dev)
|
||||
|
||||
for (i = 0; i < SAMSUNG_PWM_NUM; i++) {
|
||||
struct pwm_device *pwm = &chip->pwms[i];
|
||||
struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm);
|
||||
struct samsung_pwm_channel *chan = &our_chip->channel[i];
|
||||
|
||||
if (!chan)
|
||||
if (!(pwm->flags & PWMF_REQUESTED))
|
||||
continue;
|
||||
|
||||
if (our_chip->variant.output_mask & BIT(i))
|
||||
|
@ -203,7 +203,6 @@ static const struct pwm_ops pwm_sifive_ops = {
|
||||
.free = pwm_sifive_free,
|
||||
.get_state = pwm_sifive_get_state,
|
||||
.apply = pwm_sifive_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int pwm_sifive_clock_notifier(struct notifier_block *nb,
|
||||
|
@ -200,7 +200,6 @@ static int sl28cpld_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops sl28cpld_pwm_ops = {
|
||||
.apply = sl28cpld_pwm_apply,
|
||||
.get_state = sl28cpld_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int sl28cpld_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -189,7 +189,6 @@ static int spear_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops spear_pwm_ops = {
|
||||
.apply = spear_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int spear_pwm_probe(struct platform_device *pdev)
|
||||
@ -207,26 +206,21 @@ static int spear_pwm_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(pc->mmio_base))
|
||||
return PTR_ERR(pc->mmio_base);
|
||||
|
||||
pc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
pc->clk = devm_clk_get_prepared(&pdev->dev, NULL);
|
||||
if (IS_ERR(pc->clk))
|
||||
return PTR_ERR(pc->clk);
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
|
||||
"Failed to get clock\n");
|
||||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &spear_pwm_ops;
|
||||
pc->chip.npwm = NUM_PWM;
|
||||
|
||||
ret = clk_prepare(pc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (of_device_is_compatible(np, "st,spear1340-pwm")) {
|
||||
ret = clk_enable(pc->clk);
|
||||
if (ret) {
|
||||
clk_unprepare(pc->clk);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Failed to enable clk\n");
|
||||
|
||||
/*
|
||||
* Following enables PWM chip, channels would still be
|
||||
* enabled individually through their control register
|
||||
@ -238,23 +232,11 @@ static int spear_pwm_probe(struct platform_device *pdev)
|
||||
clk_disable(pc->clk);
|
||||
}
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
if (ret < 0) {
|
||||
clk_unprepare(pc->clk);
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
||||
}
|
||||
ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void spear_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spear_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&pc->chip);
|
||||
|
||||
/* clk was prepared in probe, hence unprepare it here */
|
||||
clk_unprepare(pc->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id spear_pwm_of_match[] = {
|
||||
@ -271,7 +253,6 @@ static struct platform_driver spear_pwm_driver = {
|
||||
.of_match_table = spear_pwm_of_match,
|
||||
},
|
||||
.probe = spear_pwm_probe,
|
||||
.remove_new = spear_pwm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(spear_pwm_driver);
|
||||
|
@ -40,6 +40,11 @@ struct sprd_pwm_chip {
|
||||
struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM];
|
||||
};
|
||||
|
||||
static inline struct sprd_pwm_chip* sprd_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct sprd_pwm_chip, chip);
|
||||
}
|
||||
|
||||
/*
|
||||
* The list of clocks required by PWM channels, and each channel has 2 clocks:
|
||||
* enable clock and pwm clock.
|
||||
@ -69,8 +74,7 @@ static void sprd_pwm_write(struct sprd_pwm_chip *spc, u32 hwid,
|
||||
static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct sprd_pwm_chip *spc =
|
||||
container_of(chip, struct sprd_pwm_chip, chip);
|
||||
struct sprd_pwm_chip *spc = sprd_pwm_from_chip(chip);
|
||||
struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];
|
||||
u32 val, duty, prescale;
|
||||
u64 tmp;
|
||||
@ -162,8 +166,7 @@ static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm,
|
||||
static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct sprd_pwm_chip *spc =
|
||||
container_of(chip, struct sprd_pwm_chip, chip);
|
||||
struct sprd_pwm_chip *spc = sprd_pwm_from_chip(chip);
|
||||
struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];
|
||||
struct pwm_state *cstate = &pwm->state;
|
||||
int ret;
|
||||
@ -210,7 +213,6 @@ static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops sprd_pwm_ops = {
|
||||
.apply = sprd_pwm_apply,
|
||||
.get_state = sprd_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc)
|
||||
@ -240,10 +242,8 @@ static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc)
|
||||
chn->clk_rate = clk_get_rate(clk_pwm);
|
||||
}
|
||||
|
||||
if (!i) {
|
||||
dev_err(spc->dev, "no available PWM channels\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!i)
|
||||
return dev_err_probe(spc->dev, -ENODEV, "no available PWM channels\n");
|
||||
|
||||
spc->num_pwms = i;
|
||||
|
||||
@ -264,7 +264,6 @@ static int sprd_pwm_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(spc->base);
|
||||
|
||||
spc->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, spc);
|
||||
|
||||
ret = sprd_pwm_clk_init(spc);
|
||||
if (ret)
|
||||
@ -274,20 +273,13 @@ static int sprd_pwm_probe(struct platform_device *pdev)
|
||||
spc->chip.ops = &sprd_pwm_ops;
|
||||
spc->chip.npwm = spc->num_pwms;
|
||||
|
||||
ret = pwmchip_add(&spc->chip);
|
||||
ret = devm_pwmchip_add(&pdev->dev, &spc->chip);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to add PWM chip\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sprd_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sprd_pwm_chip *spc = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&spc->chip);
|
||||
}
|
||||
|
||||
static const struct of_device_id sprd_pwm_of_match[] = {
|
||||
{ .compatible = "sprd,ums512-pwm", },
|
||||
{ },
|
||||
@ -300,7 +292,6 @@ static struct platform_driver sprd_pwm_driver = {
|
||||
.of_match_table = sprd_pwm_of_match,
|
||||
},
|
||||
.probe = sprd_pwm_probe,
|
||||
.remove_new = sprd_pwm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sprd_pwm_driver);
|
||||
|
@ -79,6 +79,7 @@ struct sti_pwm_compat_data {
|
||||
unsigned int cpt_num_devs;
|
||||
unsigned int max_pwm_cnt;
|
||||
unsigned int max_prescale;
|
||||
struct sti_cpt_ddata *ddata;
|
||||
};
|
||||
|
||||
struct sti_pwm_chip {
|
||||
@ -314,7 +315,7 @@ static int sti_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
{
|
||||
struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
|
||||
struct sti_pwm_compat_data *cdata = pc->cdata;
|
||||
struct sti_cpt_ddata *ddata = pwm_get_chip_data(pwm);
|
||||
struct sti_cpt_ddata *ddata = &cdata->ddata[pwm->hwpwm];
|
||||
struct device *dev = pc->dev;
|
||||
unsigned int effective_ticks;
|
||||
unsigned long long high, low;
|
||||
@ -420,7 +421,6 @@ static const struct pwm_ops sti_pwm_ops = {
|
||||
.capture = sti_pwm_capture,
|
||||
.apply = sti_pwm_apply,
|
||||
.free = sti_pwm_free,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static irqreturn_t sti_pwm_interrupt(int irq, void *data)
|
||||
@ -440,7 +440,7 @@ static irqreturn_t sti_pwm_interrupt(int irq, void *data)
|
||||
while (cpt_int_stat) {
|
||||
devicenum = ffs(cpt_int_stat) - 1;
|
||||
|
||||
ddata = pwm_get_chip_data(&pc->chip.pwms[devicenum]);
|
||||
ddata = &pc->cdata->ddata[devicenum];
|
||||
|
||||
/*
|
||||
* Capture input:
|
||||
@ -638,12 +638,23 @@ static int sti_pwm_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "failed to prepare clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cdata->ddata = devm_kzalloc(dev, cdata->cpt_num_devs * sizeof(*cdata->ddata), GFP_KERNEL);
|
||||
if (!cdata->ddata)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pc->chip.dev = dev;
|
||||
pc->chip.ops = &sti_pwm_ops;
|
||||
pc->chip.npwm = pc->cdata->pwm_num_devs;
|
||||
|
||||
for (i = 0; i < cdata->cpt_num_devs; i++) {
|
||||
struct sti_cpt_ddata *ddata = &cdata->ddata[i];
|
||||
|
||||
init_waitqueue_head(&ddata->wait);
|
||||
mutex_init(&ddata->lock);
|
||||
}
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
if (ret < 0) {
|
||||
clk_unprepare(pc->pwm_clk);
|
||||
@ -651,19 +662,6 @@ static int sti_pwm_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < cdata->cpt_num_devs; i++) {
|
||||
struct sti_cpt_ddata *ddata;
|
||||
|
||||
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
init_waitqueue_head(&ddata->wait);
|
||||
mutex_init(&ddata->lock);
|
||||
|
||||
pwm_set_chip_data(&pc->chip.pwms[i], ddata);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
|
||||
return 0;
|
||||
|
@ -189,7 +189,6 @@ static int stm32_pwm_lp_get_state(struct pwm_chip *chip,
|
||||
}
|
||||
|
||||
static const struct pwm_ops stm32_pwm_lp_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.apply = stm32_pwm_lp_apply,
|
||||
.get_state = stm32_pwm_lp_get_state,
|
||||
};
|
||||
|
@ -487,7 +487,6 @@ static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
static const struct pwm_ops stm32pwm_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.apply = stm32_pwm_apply_locked,
|
||||
.capture = IS_ENABLED(CONFIG_DMA_ENGINE) ? stm32_pwm_capture : NULL,
|
||||
};
|
||||
|
@ -287,7 +287,6 @@ static int stmpe_24xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops stmpe_24xx_pwm_ops = {
|
||||
.apply = stmpe_24xx_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init stmpe_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -325,7 +325,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops sun4i_pwm_ops = {
|
||||
.apply = sun4i_pwm_apply,
|
||||
.get_state = sun4i_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct sun4i_pwm_data sun4i_pwm_dual_nobypass = {
|
||||
|
@ -163,7 +163,6 @@ static int sunplus_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops sunplus_pwm_ops = {
|
||||
.apply = sunplus_pwm_apply,
|
||||
.get_state = sunplus_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void sunplus_pwm_clk_release(void *data)
|
||||
|
@ -268,7 +268,6 @@ static int tegra_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops tegra_pwm_ops = {
|
||||
.apply = tegra_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int tegra_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -205,7 +205,6 @@ static int ecap_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops ecap_pwm_ops = {
|
||||
.apply = ecap_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id ecap_of_match[] = {
|
||||
|
@ -437,7 +437,6 @@ static int ehrpwm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops ehrpwm_pwm_ops = {
|
||||
.free = ehrpwm_pwm_free,
|
||||
.apply = ehrpwm_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id ehrpwm_of_match[] = {
|
||||
|
@ -189,7 +189,6 @@ static int twl4030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops twl4030_pwmled_ops = {
|
||||
.apply = twl4030_pwmled_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
@ -342,7 +341,6 @@ static const struct pwm_ops twl6030_pwmled_ops = {
|
||||
.apply = twl6030_pwmled_apply,
|
||||
.request = twl6030_pwmled_request,
|
||||
.free = twl6030_pwmled_free,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int twl_pwmled_probe(struct platform_device *pdev)
|
||||
|
@ -333,12 +333,10 @@ static const struct pwm_ops twl4030_pwm_ops = {
|
||||
.apply = twl4030_pwm_apply,
|
||||
.request = twl4030_pwm_request,
|
||||
.free = twl4030_pwm_free,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct pwm_ops twl6030_pwm_ops = {
|
||||
.apply = twl6030_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int twl_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -129,7 +129,6 @@ static int visconti_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
static const struct pwm_ops visconti_pwm_ops = {
|
||||
.apply = visconti_pwm_apply,
|
||||
.get_state = visconti_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int visconti_pwm_probe(struct platform_device *pdev)
|
||||
|
@ -221,7 +221,6 @@ static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
|
||||
static const struct pwm_ops vt8500_pwm_ops = {
|
||||
.apply = vt8500_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id vt8500_pwm_dt_ids[] = {
|
||||
@ -236,10 +235,8 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "invalid devicetree node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!np)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL, "invalid devicetree node\n");
|
||||
|
||||
vt8500 = devm_kzalloc(&pdev->dev, sizeof(*vt8500), GFP_KERNEL);
|
||||
if (vt8500 == NULL)
|
||||
@ -249,45 +246,23 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
|
||||
vt8500->chip.ops = &vt8500_pwm_ops;
|
||||
vt8500->chip.npwm = VT8500_NR_PWMS;
|
||||
|
||||
vt8500->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(vt8500->clk)) {
|
||||
dev_err(&pdev->dev, "clock source not specified\n");
|
||||
return PTR_ERR(vt8500->clk);
|
||||
}
|
||||
vt8500->clk = devm_clk_get_prepared(&pdev->dev, NULL);
|
||||
if (IS_ERR(vt8500->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(vt8500->clk), "clock source not specified\n");
|
||||
|
||||
vt8500->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(vt8500->base))
|
||||
return PTR_ERR(vt8500->base);
|
||||
|
||||
ret = clk_prepare(vt8500->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to prepare clock\n");
|
||||
return ret;
|
||||
}
|
||||
ret = devm_pwmchip_add(&pdev->dev, &vt8500->chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
|
||||
|
||||
ret = pwmchip_add(&vt8500->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to add PWM chip\n");
|
||||
clk_unprepare(vt8500->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, vt8500);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vt8500_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vt8500_chip *vt8500 = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&vt8500->chip);
|
||||
|
||||
clk_unprepare(vt8500->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vt8500_pwm_driver = {
|
||||
.probe = vt8500_pwm_probe,
|
||||
.remove_new = vt8500_pwm_remove,
|
||||
.driver = {
|
||||
.name = "vt8500-pwm",
|
||||
.of_match_table = vt8500_pwm_dt_ids,
|
||||
|
@ -198,7 +198,6 @@ static int xilinx_pwm_get_state(struct pwm_chip *chip,
|
||||
static const struct pwm_ops xilinx_pwm_ops = {
|
||||
.apply = xilinx_pwm_apply,
|
||||
.get_state = xilinx_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct regmap_config xilinx_pwm_regmap_config = {
|
||||
|
@ -258,7 +258,6 @@ static const struct pwm_ops gb_pwm_ops = {
|
||||
.request = gb_pwm_request,
|
||||
.free = gb_pwm_free,
|
||||
.apply = gb_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int gb_pwm_probe(struct gbphy_device *gbphy_dev,
|
||||
|
@ -71,7 +71,6 @@ struct pwm_state {
|
||||
* @hwpwm: per-chip relative index of the PWM device
|
||||
* @pwm: global index of the PWM device
|
||||
* @chip: PWM chip providing this PWM device
|
||||
* @chip_data: chip-private data associated with the PWM device
|
||||
* @args: PWM arguments
|
||||
* @state: last applied state
|
||||
* @last: last implemented state (for PWM_DEBUG)
|
||||
@ -82,7 +81,6 @@ struct pwm_device {
|
||||
unsigned int hwpwm;
|
||||
unsigned int pwm;
|
||||
struct pwm_chip *chip;
|
||||
void *chip_data;
|
||||
|
||||
struct pwm_args args;
|
||||
struct pwm_state state;
|
||||
@ -267,7 +265,6 @@ struct pwm_capture {
|
||||
* @get_state: get the current PWM state. This function is only
|
||||
* called once per PWM device when the PWM chip is
|
||||
* registered.
|
||||
* @owner: helps prevent removal of modules exporting active PWMs
|
||||
*/
|
||||
struct pwm_ops {
|
||||
int (*request)(struct pwm_chip *chip, struct pwm_device *pwm);
|
||||
@ -278,13 +275,13 @@ struct pwm_ops {
|
||||
const struct pwm_state *state);
|
||||
int (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state);
|
||||
struct module *owner;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pwm_chip - abstract a PWM controller
|
||||
* @dev: device providing the PWMs
|
||||
* @ops: callbacks for this PWM controller
|
||||
* @owner: module providing this chip
|
||||
* @base: number of first PWM controlled by this chip
|
||||
* @npwm: number of PWMs controlled by this chip
|
||||
* @of_xlate: request a PWM device given a device tree PWM specifier
|
||||
@ -295,6 +292,7 @@ struct pwm_ops {
|
||||
struct pwm_chip {
|
||||
struct device *dev;
|
||||
const struct pwm_ops *ops;
|
||||
struct module *owner;
|
||||
int base;
|
||||
unsigned int npwm;
|
||||
|
||||
@ -383,13 +381,13 @@ static inline void pwm_disable(struct pwm_device *pwm)
|
||||
/* PWM provider APIs */
|
||||
int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
|
||||
unsigned long timeout);
|
||||
int pwm_set_chip_data(struct pwm_device *pwm, void *data);
|
||||
void *pwm_get_chip_data(struct pwm_device *pwm);
|
||||
|
||||
int pwmchip_add(struct pwm_chip *chip);
|
||||
int __pwmchip_add(struct pwm_chip *chip, struct module *owner);
|
||||
#define pwmchip_add(chip) __pwmchip_add(chip, THIS_MODULE)
|
||||
void pwmchip_remove(struct pwm_chip *chip);
|
||||
|
||||
int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip);
|
||||
int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner);
|
||||
#define devm_pwmchip_add(dev, chip) __devm_pwmchip_add(dev, chip, THIS_MODULE)
|
||||
|
||||
struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
|
||||
unsigned int index,
|
||||
@ -445,16 +443,6 @@ static inline int pwm_capture(struct pwm_device *pwm,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void *pwm_get_chip_data(struct pwm_device *pwm)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int pwmchip_add(struct pwm_chip *chip)
|
||||
{
|
||||
return -EINVAL;
|
||||
|
Loading…
Reference in New Issue
Block a user