• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
29 struct 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 
gpio_timer_func(struct hrtimer * timer)38 static 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 
gpio_get_time(struct timed_output_dev * dev)47 static 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 
gpio_enable(struct timed_output_dev * dev,int value)62 static 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 
timed_gpio_probe(struct platform_device * pdev)86 static 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 
133 err_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 
timed_gpio_remove(struct platform_device * pdev)142 static 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 
156 static 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 
164 module_platform_driver(timed_gpio_driver);
165 
166 MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
167 MODULE_DESCRIPTION("timed gpio driver");
168 MODULE_LICENSE("GPL");
169