ARM: mali400: r5p2_rel0: add sc8830 platform codes
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / char / mux.c
1 /*
2  * Copyright (C) 2012 Spreadtrum Communications Inc.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/cdev.h>
17 #include <linux/poll.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
20
21 #include <linux/sprdmux.h>
22
23 struct mux_device {
24         struct mux_init_data    *init;
25         int                     major;
26         int                     minor;
27         struct cdev             cdev;
28 };
29
30 struct mux_channel {
31         int             mux_id;
32         int             line;
33 };
34
35 static struct class             *mux_class;
36
37 static int mux_open(struct inode *inode, struct file *filp)
38 {
39         int minor = iminor(filp->f_path.dentry->d_inode);
40         struct mux_device *mux;
41         struct mux_channel *channel;
42         int rval, mux_id, line;
43
44         mux = container_of(inode->i_cdev, struct mux_device, cdev);
45
46         if (NULL == mux) {
47                 printk(KERN_ERR "MUX: Error %s mux_dev is NULL\n", __FUNCTION__);
48                 return -ENODEV;
49         }
50
51         mux_id = mux->init->id;
52
53         rval = ts0710_mux_status(mux_id);
54         if (rval != 0) {
55                 printk(KERN_ERR "MUX: Error %s [%d] mux_status is Not OK\n", __FUNCTION__, mux->init->id);
56                 filp->private_data = NULL;
57                 return -ENODEV;
58         }
59
60         printk(KERN_ERR "MUX: %s mux_id  = %d, minor = %d, mux->minor = %d\n", __FUNCTION__, mux_id , minor, mux->minor);
61
62         line = minor - mux->minor;
63
64         rval = ts0710_mux_open(mux_id, line);
65         if (rval != 0) {
66                 printk(KERN_ERR "MUX: Error %s id[%d] line[%d] mux_open is Not OK\n", __FUNCTION__, mux->init->id, line);
67                 filp->private_data = NULL;
68                 return rval;
69         }
70
71         channel = kmalloc(sizeof(struct mux_channel), GFP_KERNEL);
72         if (!channel) {
73                 return -ENOMEM;
74         }
75
76         channel->mux_id = mux_id;
77         channel->line = line;
78
79         filp->private_data = channel;
80
81         return 0;
82 }
83
84 static int mux_release(struct inode *inode, struct file *filp)
85 {
86         struct mux_channel *channel = filp->private_data;
87
88         if (channel == NULL) {
89                 printk(KERN_ERR "MUX: Error %s channel is NULL\n", __FUNCTION__);
90                 return -ENODEV;
91         }
92
93         ts0710_mux_close(channel->mux_id, channel->line);
94
95         kfree(channel);
96
97         return 0;
98 }
99
100 static ssize_t mux_read(struct file *filp,
101                 char __user *buf, size_t count, loff_t *ppos)
102 {
103         int timeout = -1;
104         struct mux_channel *channel = filp->private_data;
105
106         if (channel == NULL) {
107                 printk(KERN_ERR "MUX: Error %s channel is NULL\n", __FUNCTION__);
108                 return -ENODEV;
109         }
110
111         if (filp->f_flags & O_NONBLOCK) {
112                 timeout = 0;
113         }
114
115         return ts0710_mux_read(channel->mux_id, channel->line, buf, count, timeout);
116
117 }
118
119 static ssize_t mux_write(struct file *filp,
120                 const char __user *buf, size_t count, loff_t *ppos)
121 {
122         int timeout = -1;
123         struct mux_channel *channel = filp->private_data;
124
125         if (channel == NULL) {
126                 printk(KERN_ERR "MUX: Error %s channel is NULL\n", __FUNCTION__);
127                 return -ENODEV;
128         }
129
130         if (filp->f_flags & O_NONBLOCK) {
131                 timeout = 0;
132         }
133
134         return ts0710_mux_write(channel->mux_id, channel->line, buf, count, timeout);
135
136 }
137
138 static unsigned int mux_poll(struct file *filp, poll_table *wait)
139 {
140         struct mux_channel *channel = filp->private_data;
141
142         if (channel == NULL) {
143                 printk(KERN_ERR "MUX: Error %s channel is NULL\n", __FUNCTION__);
144                 return -ENODEV;
145         }
146
147         return ts0710_mux_poll_wait(channel->mux_id, channel->line, filp, wait);
148 }
149
150 static long mux_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
151 {
152         struct mux_channel *channel = filp->private_data;
153
154         if (channel == NULL) {
155                 printk(KERN_ERR "MUX: Error %s channel is NULL\n", __FUNCTION__);
156                 return -ENODEV;
157         }
158
159         return ts0710_mux_mux_ioctl(channel->mux_id, channel->line, cmd, arg);
160 }
161
162 static const struct file_operations mux_fops = {
163         .open           = mux_open,
164         .release        = mux_release,
165         .read           = mux_read,
166         .write          = mux_write,
167         .poll           = mux_poll,
168         .unlocked_ioctl = mux_ioctl,
169         .owner          = THIS_MODULE,
170         .llseek         = default_llseek,
171 };
172
173 static int  mux_probe(struct platform_device *pdev)
174 {
175         dev_t devid;
176         int i, rval;
177         struct mux_device *mux;
178         struct mux_init_data *init = pdev->dev.platform_data;
179
180         mux = kzalloc(sizeof(struct mux_device), GFP_KERNEL);
181         if (mux == NULL) {
182                 printk(KERN_ERR "MUX: Error %s no memory for mux\n", __FUNCTION__);
183                 return -ENOMEM;
184         }
185
186         rval = alloc_chrdev_region(&devid, 0, init->num, init->name);
187         if (rval != 0) {
188                 kfree(mux);
189                 printk(KERN_ERR "MUX: Error %s no memory for dev_region\n", __FUNCTION__);
190                 return rval;
191         }
192
193         cdev_init(&(mux->cdev), &mux_fops);
194
195         rval = cdev_add(&(mux->cdev), devid, init->num);
196         if (rval != 0) {
197                 kfree(mux);
198                 unregister_chrdev_region(devid, init->num);
199                 printk(KERN_ERR "MUX: Error %s add error\n", __FUNCTION__);
200                 return rval;
201         }
202
203         mux->major = MAJOR(devid);
204         mux->minor = MINOR(devid);
205
206         if (init->num > 1) {
207                 for (i = 0; i < init->num; i++) {
208                         device_create(mux_class, NULL,
209                                 MKDEV(mux->major, mux->minor + i),
210                                 NULL, "%s%d", init->name, i);
211                 }
212         } else {
213                 device_create(mux_class, NULL,
214                         MKDEV(mux->major, mux->minor),
215                         NULL, "%s", init->name);
216         }
217
218         mux->init = init;
219
220         platform_set_drvdata(pdev, mux);
221
222         return 0;
223 }
224
225 static int  mux_remove(struct platform_device *pdev)
226 {
227         int i;
228         struct mux_device *mux = platform_get_drvdata(pdev);
229
230         for (i = 0; i < mux->init->num; i++) {
231                 device_destroy(mux_class, MKDEV(mux->major, mux->minor + i));
232         }
233
234         cdev_del(&(mux->cdev));
235
236         unregister_chrdev_region(MKDEV(mux->major, mux->minor), mux->init->num);
237
238         kfree(mux);
239
240         platform_set_drvdata(pdev, NULL);
241
242         return 0;
243 }
244
245 static struct platform_driver mux_driver = {
246         .driver = {
247                 .owner = THIS_MODULE,
248                 .name = "mux",
249         },
250         .probe = mux_probe,
251         .remove = mux_remove,
252 };
253
254 static int __init mux_init(void)
255 {
256         printk(KERN_ERR "MUX: %s entered\n", __FUNCTION__);
257
258         ts0710_mux_init();
259
260         mux_class = class_create(THIS_MODULE, "mux");
261         if (IS_ERR(mux_class))
262                 return PTR_ERR(mux_class);
263
264         return platform_driver_register(&mux_driver);
265 }
266
267 static void __exit mux_exit(void)
268 {
269         printk(KERN_ERR "MUX: %s entered\n", __FUNCTION__);
270         ts0710_mux_exit();
271         class_destroy(mux_class);
272         platform_driver_unregister(&mux_driver);
273 }
274
275 module_init(mux_init);
276 module_exit(mux_exit);
277
278 MODULE_AUTHOR("Wu Jiaoyou");
279 MODULE_DESCRIPTION("mux driver");
280 MODULE_LICENSE("GPL");