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
  24#include "timed_output.h"
  25#include "timed_gpio.h"
  26
  27
  28struct timed_gpio_data {
  29        struct timed_output_dev dev;
  30        struct hrtimer timer;
  31        spinlock_t lock;
  32        unsigned gpio;
  33        int max_timeout;
  34        u8 active_low;
  35};
  36
  37static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer)
  38{
  39        struct timed_gpio_data *data =
  40                container_of(timer, struct timed_gpio_data, timer);
  41
  42        gpio_direction_output(data->gpio, data->active_low ? 1 : 0);
  43        return HRTIMER_NORESTART;
  44}
  45
  46static int gpio_get_time(struct timed_output_dev *dev)
  47{
  48        struct timed_gpio_data  *data =
  49                container_of(dev, struct timed_gpio_data, dev);
  50
  51        if (hrtimer_active(&data->timer)) {
  52                ktime_t r = hrtimer_get_remaining(&data->timer);
  53                struct timeval t = ktime_to_timeval(r);
  54                return t.tv_sec * 1000 + t.tv_usec / 1000;
  55        } else
  56                return 0;
  57}
  58
  59static void gpio_enable(struct timed_output_dev *dev, int value)
  60{
  61        struct timed_gpio_data  *data =
  62                container_of(dev, struct timed_gpio_data, dev);
  63        unsigned long   flags;
  64
  65        spin_lock_irqsave(&data->lock, flags);
  66
  67        /* cancel previous timer and set GPIO according to value */
  68        hrtimer_cancel(&data->timer);
  69        gpio_direction_output(data->gpio, data->active_low ? !value : !!value);
  70
  71        if (value > 0) {
  72                if (value > data->max_timeout)
  73                        value = data->max_timeout;
  74
  75                hrtimer_start(&data->timer,
  76                        ktime_set(value / 1000, (value % 1000) * 1000000),
  77                        HRTIMER_MODE_REL);
  78        }
  79
  80        spin_unlock_irqrestore(&data->lock, flags);
  81}
  82
  83static int timed_gpio_probe(struct platform_device *pdev)
  84{
  85        struct timed_gpio_platform_data *pdata = pdev->dev.platform_data;
  86        struct timed_gpio *cur_gpio;
  87        struct timed_gpio_data *gpio_data, *gpio_dat;
  88        int i, ret;
  89
  90        if (!pdata)
  91                return -EBUSY;
  92
  93        gpio_data = kzalloc(sizeof(struct timed_gpio_data) * pdata->num_gpios,
  94                        GFP_KERNEL);
  95        if (!gpio_data)
  96                return -ENOMEM;
  97
  98        for (i = 0; i < pdata->num_gpios; i++) {
  99                cur_gpio = &pdata->gpios[i];
 100                gpio_dat = &gpio_data[i];
 101
 102                hrtimer_init(&gpio_dat->timer, CLOCK_MONOTONIC,
 103                                HRTIMER_MODE_REL);
 104                gpio_dat->timer.function = gpio_timer_func;
 105                spin_lock_init(&gpio_dat->lock);
 106
 107                gpio_dat->dev.name = cur_gpio->name;
 108                gpio_dat->dev.get_time = gpio_get_time;
 109                gpio_dat->dev.enable = gpio_enable;
 110                ret = gpio_request(cur_gpio->gpio, cur_gpio->name);
 111                if (ret < 0)
 112                        goto err_out;
 113                ret = timed_output_dev_register(&gpio_dat->dev);
 114                if (ret < 0) {
 115                        gpio_free(cur_gpio->gpio);
 116                        goto err_out;
 117                }
 118
 119                gpio_dat->gpio = cur_gpio->gpio;
 120                gpio_dat->max_timeout = cur_gpio->max_timeout;
 121                gpio_dat->active_low = cur_gpio->active_low;
 122                gpio_direction_output(gpio_dat->gpio, gpio_dat->active_low);
 123        }
 124
 125        platform_set_drvdata(pdev, gpio_data);
 126
 127        return 0;
 128
 129err_out:
 130        while (--i >= 0) {
 131                timed_output_dev_unregister(&gpio_data[i].dev);
 132                gpio_free(gpio_data[i].gpio);
 133        }
 134        kfree(gpio_data);
 135
 136        return ret;
 137}
 138
 139static int timed_gpio_remove(struct platform_device *pdev)
 140{
 141        struct timed_gpio_platform_data *pdata = pdev->dev.platform_data;
 142        struct timed_gpio_data *gpio_data = platform_get_drvdata(pdev);
 143        int i;
 144
 145        for (i = 0; i < pdata->num_gpios; i++) {
 146                timed_output_dev_unregister(&gpio_data[i].dev);
 147                gpio_free(gpio_data[i].gpio);
 148        }
 149
 150        kfree(gpio_data);
 151
 152        return 0;
 153}
 154
 155static struct platform_driver timed_gpio_driver = {
 156        .probe          = timed_gpio_probe,
 157        .remove         = timed_gpio_remove,
 158        .driver         = {
 159                .name           = TIMED_GPIO_NAME,
 160                .owner          = THIS_MODULE,
 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