upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / misc / micro_usb_switch.c
1 /*
2  *  Copyright (C) 2009 Samsung Electronics
3  *  Minkyu Kang <mk7.kang@samsung.com>
4  *  
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
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  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18  *
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/slab.h>
25 #include <linux/platform_device.h>
26 #include <linux/micro_usb_switch.h>
27
28 struct micro_usb_switch {
29         struct micro_usb_switch_platform_data   *pdata;
30         int                                     path;
31 };
32
33 static ssize_t micro_usb_switch_show_state(struct device *dev,
34                 struct device_attribute *attr, char *buf)
35 {
36         struct micro_usb_switch *usb_switch=
37                         platform_get_drvdata(to_platform_device(dev));
38         struct micro_usb_switch_platform_data *pdata = usb_switch->pdata;
39         int ret;
40         int path;
41
42         path = pdata->get_usb_switch();
43
44         if (path == USB_PATH_AP)
45                 ret = sprintf(buf, "AP\n");
46         else if (path == USB_PATH_CP)
47                 ret = sprintf(buf, "CP\n");
48         else
49                 ret = sprintf(buf, "NA\n");
50
51         return ret;
52 }
53
54 static ssize_t micro_usb_switch_store_state(struct device *dev,
55                 struct device_attribute *attr, const char *buf, size_t count)
56 {
57         struct micro_usb_switch *usb_switch=
58                         platform_get_drvdata(to_platform_device(dev));
59         struct micro_usb_switch_platform_data *pdata = usb_switch->pdata;
60         int path;
61
62         if (!count)
63                 return -EINVAL;
64
65         if (!strncmp(buf, "CP", 2))
66                 path = USB_PATH_CP;
67         else if (!strncmp(buf, "AP", 2))
68                 path = USB_PATH_AP;
69         else
70                 return count;
71
72         if (path == usb_switch->path)
73                 return count;
74
75         pdata->set_usb_switch(path);
76
77         if (pdata->usb_power) {
78                 pdata->usb_power(path, USB_PATH_CP);
79                 pdata->usb_power(!path, USB_PATH_AP);
80         }
81
82         usb_switch->path = path;
83
84         return count;
85 }
86
87 static struct device_attribute micro_usb_switch_attr = {
88         .attr = {
89                 .name = "path",
90                 .mode = 0644,
91         },
92         .show = micro_usb_switch_show_state,
93         .store = micro_usb_switch_store_state,
94 };
95
96 static int __devinit usb_switch_probe(struct platform_device *pdev)
97 {
98         struct micro_usb_switch_platform_data *pdata = pdev->dev.platform_data;
99         struct micro_usb_switch *usb_switch;
100         int ret;
101
102         usb_switch = kzalloc(sizeof(struct micro_usb_switch), GFP_KERNEL);
103         if (!usb_switch) {
104                 dev_err(&pdev->dev, "failed to allocate driver data\n");
105                 return -ENOMEM;
106         }
107
108         platform_set_drvdata(pdev, usb_switch);
109         usb_switch->pdata = pdata;
110         usb_switch->path = pdata->default_path;
111
112         ret = device_create_file(&pdev->dev, &micro_usb_switch_attr);
113         if (ret) {
114                 dev_err(&pdev->dev, "failed to crreate device file\n");
115                 return ret;
116         }
117
118         return 0;
119 }
120
121 static int __devexit usb_switch_remove(struct platform_device *pdev)
122 {
123         platform_set_drvdata(pdev, NULL);
124         return 0;
125 }
126
127 static struct platform_driver usb_switch_driver = {
128         .probe          = usb_switch_probe,
129         .remove         = __devexit_p(usb_switch_remove),
130         .driver         = {
131                 .name   = "usb-switch",
132                 .owner  = THIS_MODULE,
133         },
134 };
135
136 static int __init usb_switch_init(void)
137 {
138         return platform_driver_register(&usb_switch_driver);
139 }
140 module_init(usb_switch_init);
141
142 static void __exit usb_switch_exit(void)
143 {
144         platform_driver_unregister(&usb_switch_driver);
145 }
146 module_exit(usb_switch_exit);
147
148 MODULE_AUTHOR("Minkyu Kang <mk7.kang@samsung.com>");
149 MODULE_DESCRIPTION("Micro USB Switch Driver");
150 MODULE_LICENSE("GPL");