1a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding/* 2a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding * Blackfin Pulse Width Modulation (PWM) core 3a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding * 4a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding * Copyright (c) 2011 Analog Devices Inc. 5a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding * 6a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding * Licensed under the GPL-2 or later. 7a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding */ 8a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 9a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding#include <linux/module.h> 10a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding#include <linux/platform_device.h> 11a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding#include <linux/pwm.h> 12a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding#include <linux/slab.h> 13a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 14a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding#include <asm/gptimers.h> 15a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding#include <asm/portmux.h> 16a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 17a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstruct bfin_pwm_chip { 18a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding struct pwm_chip chip; 19a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding}; 20a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 21a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstruct bfin_pwm { 22a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding unsigned short pin; 23a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding}; 24a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 25a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstatic const unsigned short pwm_to_gptimer_per[] = { 26a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5, 27a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11, 28a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding}; 29a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 30a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstatic int bfin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 31a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding{ 32a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding struct bfin_pwm *priv; 33a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding int ret; 34a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 35a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding if (pwm->hwpwm >= ARRAY_SIZE(pwm_to_gptimer_per)) 36a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding return -EINVAL; 37a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 38a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding priv = kzalloc(sizeof(*priv), GFP_KERNEL); 39a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding if (!priv) 40a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding return -ENOMEM; 41a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 42a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding priv->pin = pwm_to_gptimer_per[pwm->hwpwm]; 43a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 44a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding ret = peripheral_request(priv->pin, NULL); 45a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding if (ret) { 46a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding kfree(priv); 47a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding return ret; 48a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding } 49a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 50a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding pwm_set_chip_data(pwm, priv); 51a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 52a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding return 0; 53a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding} 54a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 55a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstatic void bfin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 56a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding{ 57a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding struct bfin_pwm *priv = pwm_get_chip_data(pwm); 58a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 59a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding if (priv) { 60a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding peripheral_free(priv->pin); 61a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding kfree(priv); 62a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding } 63a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding} 64a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 65a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstatic int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 66a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding int duty_ns, int period_ns) 67a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding{ 68a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding struct bfin_pwm *priv = pwm_get_chip_data(pwm); 69a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding unsigned long period, duty; 70a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding unsigned long long val; 71a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 72a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding val = (unsigned long long)get_sclk() * period_ns; 73a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding do_div(val, NSEC_PER_SEC); 74a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding period = val; 75a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 76a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding val = (unsigned long long)period * duty_ns; 77a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding do_div(val, period_ns); 78a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding duty = period - val; 79a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 80a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding if (duty >= period) 81a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding duty = period - 1; 82a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 83a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding set_gptimer_config(priv->pin, TIMER_MODE_PWM | TIMER_PERIOD_CNT); 84a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding set_gptimer_pwidth(priv->pin, duty); 85a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding set_gptimer_period(priv->pin, period); 86a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 87a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding return 0; 88a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding} 89a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 90a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstatic int bfin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 91a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding{ 92a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding struct bfin_pwm *priv = pwm_get_chip_data(pwm); 93a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 94a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding enable_gptimer(priv->pin); 95a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 96a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding return 0; 97a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding} 98a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 99a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstatic void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 100a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding{ 101a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding struct bfin_pwm *priv = pwm_get_chip_data(pwm); 102a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 103a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding disable_gptimer(priv->pin); 104a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding} 105a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 106a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstatic struct pwm_ops bfin_pwm_ops = { 107a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding .request = bfin_pwm_request, 108a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding .free = bfin_pwm_free, 109a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding .config = bfin_pwm_config, 110a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding .enable = bfin_pwm_enable, 111a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding .disable = bfin_pwm_disable, 112a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding .owner = THIS_MODULE, 113a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding}; 114a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 115a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstatic int bfin_pwm_probe(struct platform_device *pdev) 116a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding{ 117a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding struct bfin_pwm_chip *pwm; 118a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding int ret; 119a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 120a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); 121a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding if (!pwm) { 122a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding dev_err(&pdev->dev, "failed to allocate memory\n"); 123a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding return -ENOMEM; 124a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding } 125a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 126a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding platform_set_drvdata(pdev, pwm); 127a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 128a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding pwm->chip.dev = &pdev->dev; 129a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding pwm->chip.ops = &bfin_pwm_ops; 130a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding pwm->chip.base = -1; 131a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding pwm->chip.npwm = 12; 132a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 133a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding ret = pwmchip_add(&pwm->chip); 134a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding if (ret < 0) { 135a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); 136a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding return ret; 137a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding } 138a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 139a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding return 0; 140a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding} 141a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 14277f37917a6f2bd8635b553178bb34bdd80f08e40Bill Pembertonstatic int bfin_pwm_remove(struct platform_device *pdev) 143a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding{ 144a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding struct bfin_pwm_chip *pwm = platform_get_drvdata(pdev); 145a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 146b50675dcc3402ea456a1d59855260fcfd800fb40Axel Lin return pwmchip_remove(&pwm->chip); 147a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding} 148a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 149a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingstatic struct platform_driver bfin_pwm_driver = { 150a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding .driver = { 151a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding .name = "bfin-pwm", 1523dd0a909479c1d372341d749b4ff94cd638b57daThierry Reding .owner = THIS_MODULE, 153a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding }, 154a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding .probe = bfin_pwm_probe, 155fd1091125a1d11fcc635749d0d3dec36904a7a48Bill Pemberton .remove = bfin_pwm_remove, 156a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding}; 157a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 158a4315e3c11f97ea0fa602184fa310161309657dfThierry Redingmodule_platform_driver(bfin_pwm_driver); 159a4315e3c11f97ea0fa602184fa310161309657dfThierry Reding 160a4315e3c11f97ea0fa602184fa310161309657dfThierry RedingMODULE_LICENSE("GPL"); 161