linux/arch/blackfin/kernel/pwm.c
<<
>>
Prefs
   1/*
   2 * Blackfin Pulse Width Modulation (PWM) core
   3 *
   4 * Copyright (c) 2011 Analog Devices Inc.
   5 *
   6 * Licensed under the GPL-2 or later.
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/pwm.h>
  11#include <linux/slab.h>
  12
  13#include <asm/gptimers.h>
  14#include <asm/portmux.h>
  15
  16struct pwm_device {
  17        unsigned id;
  18        unsigned short pin;
  19};
  20
  21static const unsigned short pwm_to_gptimer_per[] = {
  22        P_TMR0, P_TMR1, P_TMR2, P_TMR3, P_TMR4, P_TMR5,
  23        P_TMR6, P_TMR7, P_TMR8, P_TMR9, P_TMR10, P_TMR11,
  24};
  25
  26struct pwm_device *pwm_request(int pwm_id, const char *label)
  27{
  28        struct pwm_device *pwm;
  29        int ret;
  30
  31        /* XXX: pwm_id really should be unsigned */
  32        if (pwm_id < 0)
  33                return NULL;
  34
  35        pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
  36        if (!pwm)
  37                return pwm;
  38
  39        pwm->id = pwm_id;
  40        if (pwm->id >= ARRAY_SIZE(pwm_to_gptimer_per))
  41                goto err;
  42
  43        pwm->pin = pwm_to_gptimer_per[pwm->id];
  44        ret = peripheral_request(pwm->pin, label);
  45        if (ret)
  46                goto err;
  47
  48        return pwm;
  49 err:
  50        kfree(pwm);
  51        return NULL;
  52}
  53EXPORT_SYMBOL(pwm_request);
  54
  55void pwm_free(struct pwm_device *pwm)
  56{
  57        peripheral_free(pwm->pin);
  58        kfree(pwm);
  59}
  60EXPORT_SYMBOL(pwm_free);
  61
  62int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
  63{
  64        unsigned long period, duty;
  65        unsigned long long val;
  66
  67        if (duty_ns < 0 || duty_ns > period_ns)
  68                return -EINVAL;
  69
  70        val = (unsigned long long)get_sclk() * period_ns;
  71        do_div(val, NSEC_PER_SEC);
  72        period = val;
  73
  74        val = (unsigned long long)period * duty_ns;
  75        do_div(val, period_ns);
  76        duty = period - val;
  77
  78        if (duty >= period)
  79                duty = period - 1;
  80
  81        set_gptimer_config(pwm->id, TIMER_MODE_PWM | TIMER_PERIOD_CNT);
  82        set_gptimer_pwidth(pwm->id, duty);
  83        set_gptimer_period(pwm->id, period);
  84
  85        return 0;
  86}
  87EXPORT_SYMBOL(pwm_config);
  88
  89int pwm_enable(struct pwm_device *pwm)
  90{
  91        enable_gptimer(pwm->id);
  92        return 0;
  93}
  94EXPORT_SYMBOL(pwm_enable);
  95
  96void pwm_disable(struct pwm_device *pwm)
  97{
  98        disable_gptimer(pwm->id);
  99}
 100EXPORT_SYMBOL(pwm_disable);
 101