blob: 97a511e80eddf42d138999d783ee2529f7271814 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/errno.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/kernel.h>
17#include <linux/uaccess.h>
18#include <linux/version.h>
19#include <linux/debugfs.h>
20#include <linux/kernel.h>
21#include <linux/param.h>
22#include <linux/platform_device.h>
23#include <linux/gpio.h>
24#include <mach/gpio.h>
25#include <mach/vreg.h>
Rohit Vaswania513aa8d2011-07-18 15:14:28 -070026#include <mach/gpiomux.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027
28#define VERSION "1.0"
29struct dentry *pin_debugfs_dent;
30
31/* UART GPIO lines for 8660 */
32enum uartpins {
33 UARTDM_TX = 53,
34 UARTDM_RX = 54,
35 UARTDM_CTS = 55,
36 UARTDM_RFR = 56
37};
38
39/* Aux PCM GPIO lines for 8660 */
40enum auxpcmpins {
41 AUX_PCM_CLK = 114,
42 AUX_PCM_SYNC = 113,
43 AUX_PCM_DIN = 112,
44 AUX_PCM_DOUT = 111
45};
46/*Number of UART and PCM pins */
47#define PIN_COUNT 8
48
49static struct gpiomux_setting pin_test_config = {
50 .func = GPIOMUX_FUNC_GPIO,
51 .drv = GPIOMUX_DRV_2MA,
52 .pull = GPIOMUX_PULL_NONE,
53};
54/* Static array to intialise the return config */
55static struct gpiomux_setting currentconfig[2*PIN_COUNT];
56
57static struct msm_gpiomux_config pin_test_configs[] = {
58 {
59 .gpio = AUX_PCM_DOUT,
60 .settings = {
61 [GPIOMUX_ACTIVE] = &pin_test_config,
62 [GPIOMUX_SUSPENDED] = &pin_test_config,
63 },
64 },
65 {
66 .gpio = AUX_PCM_DIN,
67 .settings = {
68 [GPIOMUX_ACTIVE] = &pin_test_config,
69 [GPIOMUX_SUSPENDED] = &pin_test_config,
70 },
71 },
72 {
73 .gpio = AUX_PCM_SYNC,
74 .settings = {
75 [GPIOMUX_ACTIVE] = &pin_test_config,
76 [GPIOMUX_SUSPENDED] = &pin_test_config,
77 },
78 },
79 {
80 .gpio = AUX_PCM_CLK,
81 .settings = {
82 [GPIOMUX_ACTIVE] = &pin_test_config,
83 [GPIOMUX_SUSPENDED] = &pin_test_config,
84 },
85 },
86 {
87 .gpio = UARTDM_TX,
88 .settings = {
89 [GPIOMUX_ACTIVE] = &pin_test_config,
90 [GPIOMUX_SUSPENDED] = &pin_test_config,
91 },
92 },
93 {
94 .gpio = UARTDM_RX,
95 .settings = {
96 [GPIOMUX_ACTIVE] = &pin_test_config,
97 [GPIOMUX_SUSPENDED] = &pin_test_config,
98 },
99 },
100 {
101 .gpio = UARTDM_CTS,
102 .settings = {
103 [GPIOMUX_ACTIVE] = &pin_test_config,
104 [GPIOMUX_SUSPENDED] = &pin_test_config,
105 },
106 },
107 {
108 .gpio = UARTDM_RFR,
109 .settings = {
110 [GPIOMUX_ACTIVE] = &pin_test_config,
111 [GPIOMUX_SUSPENDED] = &pin_test_config,
112 },
113 },
114};
115static struct msm_gpiomux_config pin_config[PIN_COUNT];
116
117static int pintest_open(struct inode *inode, struct file *file)
118{
119 /* non-seekable */
120 file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
121 return 0;
122}
123
124static int pintest_release(struct inode *inode, struct file *file)
125{
126 return 0;
127}
128
129static int configure_pins(struct msm_gpiomux_config *config,
130 struct msm_gpiomux_config *oldconfig,
131 unsigned int num_configs)
132{
133 int rc = 0, j, i;
134 for (i = 0; i < num_configs; i++) {
135 for (j = 0; j < GPIOMUX_NSETTINGS; j++) {
136 (oldconfig + i)->gpio = (config + i)->gpio;
137 rc = msm_gpiomux_write((config + i)->gpio,
138 j,
139 (config + i)->settings[j],
140 (oldconfig + i)->settings[j]);
141 if (rc < 0)
142 break;
143 }
144
145 }
146 return rc;
147}
148
149static void init_current_config_pointers(void)
150{
151 int i = 0, j = 0;
152 /* The current config variables will hold the current configuration
153 * which is getting overwritten during a msm_gpiomux_write call
154 */
155 for (i = 0, j = 0; i < PIN_COUNT; i += 1, j += 2) {
156 pin_config[i].settings[GPIOMUX_ACTIVE] = &currentconfig[j];
157 pin_config[i].settings[GPIOMUX_SUSPENDED] =
158 &currentconfig[j + 1];
159 }
160
161}
162
163static ssize_t pintest_write(
164 struct file *file,
165 const char __user *buff,
166 size_t count,
167 loff_t *ppos)
168{
169 char mode;
170 int rc = 0;
171
172 if (count < 1)
173 return -EINVAL;
174
175 if (buff == NULL)
176 return -EINVAL;
177
178 if (copy_from_user(&mode, buff, count))
179 return -EFAULT;
180 mode = mode - '0';
181
182 init_current_config_pointers();
183
184 if (mode) {
185 /* Configure all pin test gpios for the custom settings */
186 rc = configure_pins(pin_test_configs, pin_config,
187 ARRAY_SIZE(pin_test_configs));
188 if (rc < 0)
189 return rc;
190 } else {
191 /* Configure all pin test gpios for the original settings */
192 rc = configure_pins(pin_config, pin_test_configs,
193 ARRAY_SIZE(pin_test_configs));
194 if (rc < 0)
195 return rc;
196 }
197 return rc;
198}
199
200static const struct file_operations pintest_debugfs_fops = {
201 .open = pintest_open,
202 .release = pintest_release,
203 .write = pintest_write,
204};
205
206static int __init bluepintest_init(void)
207{
208 pin_debugfs_dent = debugfs_create_dir("btpintest", NULL);
209
210 if (IS_ERR(pin_debugfs_dent)) {
211 printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n",
212 __FILE__, __LINE__, PTR_ERR(pin_debugfs_dent));
213 return -ENOMEM;
214 }
215
216 if (debugfs_create_file("enable", 0644, pin_debugfs_dent,
217 0, &pintest_debugfs_fops) == NULL) {
218 printk(KERN_ERR "%s(%d): debugfs_create_file: index fail\n",
219 __FILE__, __LINE__);
220 return -ENOMEM;
221 }
222 return 0;
223}
224
225static void __exit bluepintest_exit(void)
226{
227 debugfs_remove_recursive(pin_debugfs_dent);
228}
229
230module_init(bluepintest_init);
231module_exit(bluepintest_exit);
232
233MODULE_DESCRIPTION("Bluetooth Pin Connectivty Test Driver ver %s " VERSION);
234MODULE_LICENSE("GPL v2");