PageRenderTime 72ms CodeModel.GetById 37ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/misc/sun4i-gpio.c

https://bitbucket.org/ndreys/linux-sunxi
C | 269 lines | 204 code | 49 blank | 16 comment | 19 complexity | 57d8a0a4a8a6ba760428ffefa919a307 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/* driver/misc/sun4i-gpio.c
  2 *
  3 *  Copyright (C) 2011 Allwinner Technology Co.Ltd
  4 *   Tom Cubie <tangliang@allwinnertech.com>
  5 *
  6 *  www.allwinnertech.com
  7 *
  8 *  An ugly sun4i gpio driver
  9 *
 10 * This program is free software; you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License version 2 as
 12 * published by the Free Software Foundation.
 13 *
 14 */
 15
 16#include <linux/module.h>
 17#include <linux/init.h>
 18#include <linux/pm.h>
 19#include <linux/sysdev.h>
 20#include <linux/fs.h>
 21#include <linux/kernel.h>
 22#include <linux/slab.h>
 23#include <linux/earlysuspend.h>
 24#include <linux/miscdevice.h>
 25#include <linux/device.h>
 26
 27#include <mach/sys_config.h>
 28
 29#undef DEBUG_SUN4I
 30
 31#ifdef DEBUG_SUN4I
 32#define sun4i_gpio_dbg(x...)	printk(x)
 33#else
 34#define sun4i_gpio_dbg(x...)
 35#endif
 36
 37struct sun4i_gpio_data {
 38	int status;
 39	unsigned gpio_handler;
 40	script_gpio_set_t info;
 41	char name[8];
 42#ifdef CONFIG_HAS_EARLYSUSPEND
 43	struct early_suspend early_suspend;
 44#endif
 45};
 46
 47static int sun4i_gpio_num;
 48static struct sun4i_gpio_data *psun4i_gpio;
 49static struct device_attribute *pattr;
 50
 51static void set_sun4i_gpio_status(struct sun4i_gpio_data *sun4i_gpio,  int on)
 52{
 53	if(on) {
 54		sun4i_gpio_dbg("\n-on-");
 55		gpio_write_one_pin_value(sun4i_gpio->gpio_handler, 1, NULL);
 56	}
 57	else{
 58		sun4i_gpio_dbg("\n-off-");
 59		gpio_write_one_pin_value(sun4i_gpio->gpio_handler, 0, NULL);
 60	}
 61}
 62
 63static ssize_t sun4i_gpio_enable_store(struct device *dev,
 64				struct device_attribute *attr,
 65				const char *buf, size_t count)
 66{
 67	unsigned long data;
 68	int i,error;
 69	struct sun4i_gpio_data *gpio_i = psun4i_gpio;
 70
 71	error = strict_strtoul(buf, 10, &data);
 72	if (error)
 73		return error;
 74
 75	for(i = 0; i < sun4i_gpio_num; i++) {
 76		sun4i_gpio_dbg("%s\n", attr->attr.name);
 77		sun4i_gpio_dbg("%s\n", gpio_i->name);
 78
 79		if(!strcmp(attr->attr.name, gpio_i->name)) {
 80			set_sun4i_gpio_status(gpio_i, data);
 81			break;
 82		}
 83		gpio_i++;
 84	}
 85
 86	return count;
 87}
 88
 89static ssize_t sun4i_gpio_enable_show(struct device *dev,
 90		struct device_attribute *attr, char *buf)
 91{
 92	int i;
 93	int data = EGPIO_FAIL;
 94	struct sun4i_gpio_data *gpio_i = psun4i_gpio;
 95
 96	for(i = 0; i < sun4i_gpio_num; i++) {
 97		sun4i_gpio_dbg("%s\n", attr->attr.name);
 98		sun4i_gpio_dbg("%s\n", gpio_i->name);
 99
100		if(!strcmp(attr->attr.name, gpio_i->name)) {
101			data = gpio_read_one_pin_value(gpio_i->gpio_handler, NULL);
102			sun4i_gpio_dbg("handler:%d\n", gpio_i->gpio_handler);
103			sun4i_gpio_dbg("data:%d\n", data);
104			break;
105		}
106		gpio_i++;
107	}
108
109	if(data != EGPIO_FAIL) {
110		return sprintf(buf, "%d\n", data);
111	} else {
112		return sprintf(buf, "error\n");
113	}
114}
115
116static struct attribute *sun4i_gpio_attributes[256] = {
117	NULL
118};
119
120static struct attribute_group sun4i_gpio_attribute_group = {
121	.name = "pin",
122	.attrs = sun4i_gpio_attributes
123};
124
125static int sun4i_gpio_open(struct inode *inode, struct file *file) {
126	pr_info("sun4i_gpio open\n");
127	return 0;
128}
129
130ssize_t sun4i_gpio_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) {
131	pr_info("sun4i_gpio write\n");
132	return 0;
133}
134
135static int sun4i_gpio_release(struct inode *inode, struct file *file) {
136	gpio_release(psun4i_gpio->gpio_handler, 0);
137	kfree(psun4i_gpio);
138	return 0;
139}
140
141static const struct file_operations sun4i_gpio_fops = {
142	.open		= sun4i_gpio_open,
143	.write		= sun4i_gpio_write,
144	.release	= sun4i_gpio_release
145};
146
147static struct miscdevice sun4i_gpio_dev = {
148	.minor =	MISC_DYNAMIC_MINOR,
149	.name =		"sun4i-gpio",
150	.fops =		&sun4i_gpio_fops
151};
152
153static int __init sun4i_gpio_init(void) {
154	int err;
155	int i;
156	int sun4i_gpio_used = 0;
157	struct sun4i_gpio_data *gpio_i;
158	struct device_attribute *attr_i;
159	char pin[16];
160
161	pr_info("sun4i gpio driver init\n");
162
163	err = script_parser_fetch("gpio_para", "gpio_used", &sun4i_gpio_used, sizeof(sun4i_gpio_used)/sizeof(int));
164	if(err) {
165		pr_err("%s script_parser_fetch \"gpio_para\" \"gpio_used\" error\n", __FUNCTION__);
166		goto exit;
167	}
168
169	if(!sun4i_gpio_used) {
170		pr_err("%s sun4i_gpio is not used in config\n", __FUNCTION__);
171		err = -1;
172		goto exit;
173	}
174
175	err = script_parser_fetch("gpio_para", "gpio_num", &sun4i_gpio_num, sizeof(sun4i_gpio_num)/sizeof(int));
176	if(err) {
177		pr_err("%s script_parser_fetch \"gpio_para\" \"gpio_num\" error\n", __FUNCTION__);
178		goto exit;
179	}
180
181	sun4i_gpio_dbg("sun4i_gpio_num:%d\n", sun4i_gpio_num);
182	if(!sun4i_gpio_num) {
183		pr_err("%s sun4i_gpio_num is none\n", __FUNCTION__);
184		err = -1;
185		goto exit;
186	}
187
188	err = misc_register(&sun4i_gpio_dev);
189	if(err) {
190		pr_err("%s register sun4i_gpio as misc device error\n", __FUNCTION__);
191		goto exit;
192	}
193
194	psun4i_gpio = kzalloc(sizeof(struct sun4i_gpio_data) * sun4i_gpio_num, GFP_KERNEL);
195	pattr = kzalloc(sizeof(struct device_attribute) * sun4i_gpio_num, GFP_KERNEL);
196
197	if(!psun4i_gpio || !pattr) {
198		pr_err("%s kzalloc failed\n", __FUNCTION__);
199		err = -ENOMEM;
200		goto exit;
201	}
202
203	gpio_i = psun4i_gpio;
204	attr_i = pattr;
205
206	for(i = 0; i < sun4i_gpio_num; i++) {
207
208		sprintf(pin, "gpio_pin_%d", i+1);
209		sun4i_gpio_dbg("pin:%s\n", pin);
210
211		err = script_parser_fetch("gpio_para", pin,
212					(int *)&gpio_i->info, sizeof(script_gpio_set_t));
213
214		if(err) {
215			pr_err("%s script_parser_fetch \"gpio_para\" \"%s\" error\n", __FUNCTION__, pin);
216			break;
217		}
218
219		gpio_i->gpio_handler = gpio_request_ex("gpio_para", pin);
220		sun4i_gpio_dbg("gpio handler: %d", gpio_i->gpio_handler);
221
222		if(!gpio_i->gpio_handler) {
223			pr_err("%s can not get \"gpio_para\" \"%s\" gpio handler,\
224					already used by others?", __FUNCTION__, pin);
225			break;
226		}
227
228		sun4i_gpio_dbg("%s: port:%d, portnum:%d\n", pin, gpio_i->info.port,
229				gpio_i->info.port_num);
230
231		/* Turn the name to pa1, pb2 etc... */
232		sprintf(gpio_i->name, "p%c%d", 'a'+gpio_i->info.port-1, gpio_i->info.port_num);
233
234		sun4i_gpio_dbg("psun4i_gpio->name%s\n", gpio_i->name);
235
236		/* Add attributes to the group */
237		sysfs_attr_init(&attr_i->attr);
238		attr_i->attr.name = gpio_i->name;
239		attr_i->attr.mode = S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH;
240		attr_i->show = sun4i_gpio_enable_show;
241		attr_i->store = sun4i_gpio_enable_store;
242		sun4i_gpio_attributes[i] = &attr_i->attr;
243
244		gpio_i++;
245		attr_i++;
246	}
247
248	sysfs_create_group(&sun4i_gpio_dev.this_device->kobj,
249						 &sun4i_gpio_attribute_group);
250exit:
251	return err;
252}
253
254static void __exit sun4i_gpio_exit(void) {
255
256	sun4i_gpio_dbg("bye, sun4i_gpio exit\n");
257	misc_deregister(&sun4i_gpio_dev);
258	sysfs_remove_group(&sun4i_gpio_dev.this_device->kobj,
259						 &sun4i_gpio_attribute_group);
260	kfree(psun4i_gpio);
261	kfree(pattr);
262}
263
264module_init(sun4i_gpio_init);
265module_exit(sun4i_gpio_exit);
266
267MODULE_DESCRIPTION("a simple sun4i_gpio driver");
268MODULE_AUTHOR("Tom Cubie");
269MODULE_LICENSE("GPL");