linux/drivers/staging/android/timed_gpio.c
<<
>>
Prefs
   1/* drivers/misc/timed_gpio.c
   2 *
   3 * Copyright (C) 2008 Google, Inc.
   4 * Author: Mike Lockwood <lockwood@android.com>
   5 *
   6 * This software is licensed under the terms of the GNU General Public
   7 * License version 2, as published by the Free Software Foundation, and
   8 * may be copied, distributed, and modified under those terms.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/platform_device.h>
  19#include <linux/slab.h>
  20#include <linux/hrtimer.h>
  21#include <linux/err.h>
  22#include <linux/gpio.h>
  23#include <linux/ktime.h>
  24
  25#include "timed_output.h"
  26#include "timed_gpio.h"
  27
  28
  29struct timed_gpio_data {
  30        struct timed_output_dev dev;
  31        struct hrtimer timer;
  32        spinlock_t lock;
  33        unsigned gpio;
  34        int max_timeout;
  35        u8 active_low;
  36};
  37
  38static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer)
  39{
  40        struct timed_gpio_data *data =
  41                container_of(timer, struct timed_gpio_data, timer);
  42
  43        gpio_direction_output(data->gpio, data->active_low ? 1 : 0);
  44        return HRTIMER_NORESTART;
  45}
  46
  47static int gpio_get_time(struct timed_output_dev *dev)
  48{
  49        struct timed_gpio_data *data;
  50        ktime_t t;
  51
  52        data = container_of(dev, struct timed_gpio_data, dev);
  53
  54        if (!hrtimer_active(&data->timer))
  55                return 0;
  56
  57        t = hrtimer_get_remaining(&data->timer);
  58
  59        return ktime_to_ms(t);
  60}
  61
  62static void gpio_enable(struct timed_output_dev *dev, int value)
  63{
  64        struct timed_gpio_data  *data =
  65                container_of(dev, struct timed_gpio_data, dev);
  66        unsigned long   flags;
  67
  68        spin_lock_irqsave(&data->lock, flags);
  69
  70        /* cancel previous timer and set GPIO according to value */
  71        hrtimer_cancel(&data->timer);
  72        gpio_direction_output(data->gpio, data->active_low ? !value : !!value);
  73
  74        if (value > 0) {
  75                if (value > data->max_timeout)
  76                        value = data->max_timeout;
  77
  78                hrtimer_start(&data->timer,
  79                        ktime_set(value / 1000, (value % 1000) * 1000000),
  80                        HRTIMER_MODE_REL);
  81        }
  82
  83        spin_unlock_irqrestore(&data->lock, flags);
  84}
  85
  86static int timed_gpio_probe(struct platform_device *pdev)
  87{
  88        struct timed_gpio_platform_data *pdata = pdev->dev.platform_data;
  89        struct timed_gpio *cur_gpio;
  90        struct timed_gpio_data *gpio_data, *gpio_dat;
  91        int i, ret;
  92
  93        if (!pdata)
  94                return -EBUSY;
  95
  96        gpio_data = devm_kzalloc(&pdev->dev,
  97                        sizeof(struct timed_gpio_data) * pdata->num_gpios,
  98                        GFP_KERNEL);
  99        if (!gpio_data)
 100                return -ENOMEM;
 101
 102        for (i = 0; i < pdata->num_gpios; i++) {
 103                cur_gpio = &pdata->gpios[i];
 104                gpio_dat = &gpio_data[i];
 105
 106                hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC,
 107                                HRTIMER_MODE_REL);
 108                gpio_dat->timer.function = gpio_timer_func;
 109                spin_lock_init(&gpio_dat->lock);
 110
 111                gpio_dat->dev.name = cur_gpio->name;
 112                gpio_dat->dev.get_time = gpio_get_time;
 113                gpio_dat->dev.enable = gpio_enable;
 114                ret = gpio_request(cur_gpio->gpio, cur_gpio->name);
 115                if (ret < 0)
 116                        goto err_out;
 117                ret = timed_output_dev_register(&gpio_dat->dev);
 118                if (ret < 0) {
 119                        gpio_free(cur_gpio->gpio);
 120                        goto err_out;
 121                }
 122
 123                gpio_dat->gpio = cur_gpio->gpio;
 124                gpio_dat->max_timeout = cur_gpio->max_timeout;
 125                gpio_dat->active_low = cur_gpio->active_low;
 126                gpio_direction_output(gpio_dat->gpio, gpio_dat->active_low);
 127        }
 128
 129        platform_set_drvdata(pdev, gpio_data);
 130
 131        return 0;
 132
 133err_out:
 134        while (--i >= 0) {
 135                timed_output_dev_unregister(&gpio_data[i].dev);
 136                gpio_free(gpio_data[i].gpio);
 137        }
 138
 139        return ret;
 140}
 141
 142static int timed_gpio_remove(struct platform_device *pdev)
 143{
 144        struct timed_gpio_platform_data *pdata = pdev->dev.platform_data;
 145        struct timed_gpio_data *gpio_data = platform_get_drvdata(pdev);
 146        int i;
 147
 148        for (i = 0; i < pdata->num_gpios; i++) {
 149                timed_output_dev_unregister(&gpio_data[i].dev);
 150                gpio_free(gpio_data[i].gpio);
 151        }
 152
 153        return 0;
 154}
 155
 156static struct platform_driver timed_gpio_driver = {
 157        .probe          = timed_gpio_probe,
 158        .remove         = timed_gpio_remove,
 159        .driver         = {
 160                .name           = TIMED_GPIO_NAME,
 161        },
 162};
 163
 164module_platform_driver(timed_gpio_driver);
 165
 166MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
 167MODULE_DESCRIPTION("timed gpio driver");
 168MODULE_LICENSE("GPL");
 169