Commit | Line | Data |
---|---|---|
d0088ce1 PS |
1 | /* |
2 | * Shared Transport Line discipline driver Core | |
3 | * Init Manager module responsible for GPIO control | |
4 | * and firmware download | |
a0cc2f3b PS |
5 | * Copyright (C) 2009-2010 Texas Instruments |
6 | * Author: Pavan Savoy <pavan_savoy@ti.com> | |
d0088ce1 PS |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | #define pr_fmt(fmt) "(stk) :" fmt | |
24 | #include <linux/platform_device.h> | |
25 | #include <linux/jiffies.h> | |
26 | #include <linux/firmware.h> | |
27 | #include <linux/delay.h> | |
28 | #include <linux/wait.h> | |
29 | #include <linux/gpio.h> | |
c1afac15 PS |
30 | #include <linux/debugfs.h> |
31 | #include <linux/seq_file.h> | |
d0088ce1 | 32 | #include <linux/sched.h> |
773d6790 | 33 | #include <linux/sysfs.h> |
ec60d0ad | 34 | #include <linux/tty.h> |
d0088ce1 | 35 | |
5c88b021 | 36 | #include <linux/skbuff.h> |
e5558679 | 37 | #include <linux/ti_wilink_st.h> |
eb12a679 | 38 | #include <linux/module.h> |
46d0d333 GJ |
39 | #include <linux/of.h> |
40 | #include <linux/of_device.h> | |
d0088ce1 | 41 | |
dbd3a870 | 42 | #define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */ |
73f12e8d | 43 | static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; |
d0088ce1 PS |
44 | |
45 | /**********************************************************************/ | |
46 | /* internal functions */ | |
47 | ||
46d0d333 GJ |
48 | struct ti_st_plat_data *dt_pdata; |
49 | static struct ti_st_plat_data *get_platform_data(struct device *dev); | |
50 | ||
dbd3a870 PS |
51 | /** |
52 | * st_get_plat_device - | |
53 | * function which returns the reference to the platform device | |
54 | * requested by id. As of now only 1 such device exists (id=0) | |
55 | * the context requesting for reference can get the id to be | |
56 | * requested by a. The protocol driver which is registering or | |
57 | * b. the tty device which is opened. | |
58 | */ | |
59 | static struct platform_device *st_get_plat_device(int id) | |
60 | { | |
61 | return st_kim_devices[id]; | |
62 | } | |
63 | ||
36b5aee4 PS |
64 | /** |
65 | * validate_firmware_response - | |
66 | * function to return whether the firmware response was proper | |
67 | * in case of error don't complete so that waiting for proper | |
68 | * response times out | |
d0088ce1 | 69 | */ |
27712b39 | 70 | static void validate_firmware_response(struct kim_data_s *kim_gdata) |
d0088ce1 | 71 | { |
38d9df49 | 72 | struct sk_buff *skb = kim_gdata->rx_skb; |
8565adbc PS |
73 | if (!skb) |
74 | return; | |
75 | ||
76 | /* these magic numbers are the position in the response buffer which | |
77 | * allows us to distinguish whether the response is for the read | |
78 | * version info. command | |
79 | */ | |
80 | if (skb->data[2] == 0x01 && skb->data[3] == 0x01 && | |
81 | skb->data[4] == 0x10 && skb->data[5] == 0x00) { | |
82 | /* fw version response */ | |
83 | memcpy(kim_gdata->resp_buffer, | |
84 | kim_gdata->rx_skb->data, | |
85 | kim_gdata->rx_skb->len); | |
86 | complete_all(&kim_gdata->kim_rcvd); | |
87 | kim_gdata->rx_state = ST_W4_PACKET_TYPE; | |
88 | kim_gdata->rx_skb = NULL; | |
89 | kim_gdata->rx_count = 0; | |
90 | } else if (unlikely(skb->data[5] != 0)) { | |
d0088ce1 PS |
91 | pr_err("no proper response during fw download"); |
92 | pr_err("data6 %x", skb->data[5]); | |
76ff0e64 | 93 | kfree_skb(skb); |
d0088ce1 PS |
94 | return; /* keep waiting for the proper response */ |
95 | } | |
96 | /* becos of all the script being downloaded */ | |
97 | complete_all(&kim_gdata->kim_rcvd); | |
98 | kfree_skb(skb); | |
99 | } | |
100 | ||
101 | /* check for data len received inside kim_int_recv | |
102 | * most often hit the last case to update state to waiting for data | |
103 | */ | |
38d9df49 | 104 | static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len) |
d0088ce1 PS |
105 | { |
106 | register int room = skb_tailroom(kim_gdata->rx_skb); | |
107 | ||
e6d9e64e | 108 | pr_debug("len %d room %d", len, room); |
d0088ce1 PS |
109 | |
110 | if (!len) { | |
38d9df49 | 111 | validate_firmware_response(kim_gdata); |
d0088ce1 PS |
112 | } else if (len > room) { |
113 | /* Received packet's payload length is larger. | |
114 | * We can't accommodate it in created skb. | |
115 | */ | |
116 | pr_err("Data length is too large len %d room %d", len, | |
117 | room); | |
118 | kfree_skb(kim_gdata->rx_skb); | |
119 | } else { | |
120 | /* Packet header has non-zero payload length and | |
121 | * we have enough space in created skb. Lets read | |
122 | * payload data */ | |
5c88b021 | 123 | kim_gdata->rx_state = ST_W4_DATA; |
d0088ce1 PS |
124 | kim_gdata->rx_count = len; |
125 | return len; | |
126 | } | |
127 | ||
128 | /* Change ST LL state to continue to process next | |
129 | * packet */ | |
130 | kim_gdata->rx_state = ST_W4_PACKET_TYPE; | |
131 | kim_gdata->rx_skb = NULL; | |
132 | kim_gdata->rx_count = 0; | |
133 | ||
134 | return 0; | |
135 | } | |
136 | ||
36b5aee4 PS |
137 | /** |
138 | * kim_int_recv - receive function called during firmware download | |
139 | * firmware download responses on different UART drivers | |
140 | * have been observed to come in bursts of different | |
141 | * tty_receive and hence the logic | |
d0088ce1 | 142 | */ |
27712b39 | 143 | static void kim_int_recv(struct kim_data_s *kim_gdata, |
38d9df49 | 144 | const unsigned char *data, long count) |
d0088ce1 | 145 | { |
73f12e8d | 146 | const unsigned char *ptr; |
73f12e8d | 147 | int len = 0, type = 0; |
5c88b021 | 148 | unsigned char *plen; |
d0088ce1 | 149 | |
e6d9e64e | 150 | pr_debug("%s", __func__); |
d0088ce1 | 151 | /* Decode received bytes here */ |
73f12e8d | 152 | ptr = data; |
d0088ce1 PS |
153 | if (unlikely(ptr == NULL)) { |
154 | pr_err(" received null from TTY "); | |
155 | return; | |
156 | } | |
73f12e8d | 157 | |
d0088ce1 PS |
158 | while (count) { |
159 | if (kim_gdata->rx_count) { | |
160 | len = min_t(unsigned int, kim_gdata->rx_count, count); | |
161 | memcpy(skb_put(kim_gdata->rx_skb, len), ptr, len); | |
162 | kim_gdata->rx_count -= len; | |
163 | count -= len; | |
164 | ptr += len; | |
165 | ||
166 | if (kim_gdata->rx_count) | |
167 | continue; | |
168 | ||
169 | /* Check ST RX state machine , where are we? */ | |
170 | switch (kim_gdata->rx_state) { | |
171 | /* Waiting for complete packet ? */ | |
5c88b021 | 172 | case ST_W4_DATA: |
e6d9e64e | 173 | pr_debug("Complete pkt received"); |
38d9df49 | 174 | validate_firmware_response(kim_gdata); |
d0088ce1 PS |
175 | kim_gdata->rx_state = ST_W4_PACKET_TYPE; |
176 | kim_gdata->rx_skb = NULL; | |
177 | continue; | |
178 | /* Waiting for Bluetooth event header ? */ | |
5c88b021 PS |
179 | case ST_W4_HEADER: |
180 | plen = | |
181 | (unsigned char *)&kim_gdata->rx_skb->data[1]; | |
182 | pr_debug("event hdr: plen 0x%02x\n", *plen); | |
183 | kim_check_data_len(kim_gdata, *plen); | |
d0088ce1 PS |
184 | continue; |
185 | } /* end of switch */ | |
186 | } /* end of if rx_state */ | |
187 | switch (*ptr) { | |
188 | /* Bluetooth event packet? */ | |
5c88b021 PS |
189 | case 0x04: |
190 | kim_gdata->rx_state = ST_W4_HEADER; | |
191 | kim_gdata->rx_count = 2; | |
192 | type = *ptr; | |
d0088ce1 PS |
193 | break; |
194 | default: | |
195 | pr_info("unknown packet"); | |
196 | ptr++; | |
197 | count--; | |
198 | continue; | |
36b5aee4 | 199 | } |
d0088ce1 PS |
200 | ptr++; |
201 | count--; | |
202 | kim_gdata->rx_skb = | |
5c88b021 | 203 | alloc_skb(1024+8, GFP_ATOMIC); |
d0088ce1 PS |
204 | if (!kim_gdata->rx_skb) { |
205 | pr_err("can't allocate mem for new packet"); | |
206 | kim_gdata->rx_state = ST_W4_PACKET_TYPE; | |
207 | kim_gdata->rx_count = 0; | |
208 | return; | |
36b5aee4 | 209 | } |
5c88b021 PS |
210 | skb_reserve(kim_gdata->rx_skb, 8); |
211 | kim_gdata->rx_skb->cb[0] = 4; | |
212 | kim_gdata->rx_skb->cb[1] = 0; | |
213 | ||
36b5aee4 | 214 | } |
d0088ce1 PS |
215 | return; |
216 | } | |
217 | ||
38d9df49 | 218 | static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) |
d0088ce1 PS |
219 | { |
220 | unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0; | |
73f12e8d | 221 | const char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 }; |
3f46d81a | 222 | long timeout; |
d0088ce1 | 223 | |
e6d9e64e | 224 | pr_debug("%s", __func__); |
d0088ce1 | 225 | |
16735d02 | 226 | reinit_completion(&kim_gdata->kim_rcvd); |
d0088ce1 PS |
227 | if (4 != st_int_write(kim_gdata->core_data, read_ver_cmd, 4)) { |
228 | pr_err("kim: couldn't write 4 bytes"); | |
70442664 | 229 | return -EIO; |
d0088ce1 PS |
230 | } |
231 | ||
3f46d81a NMG |
232 | timeout = wait_for_completion_interruptible_timeout( |
233 | &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME)); | |
234 | if (timeout <= 0) { | |
235 | pr_err(" waiting for ver info- timed out or received signal"); | |
236 | return timeout ? -ERESTARTSYS : -ETIMEDOUT; | |
d0088ce1 | 237 | } |
16735d02 | 238 | reinit_completion(&kim_gdata->kim_rcvd); |
8565adbc PS |
239 | /* the positions 12 & 13 in the response buffer provide with the |
240 | * chip, major & minor numbers | |
241 | */ | |
d0088ce1 PS |
242 | |
243 | version = | |
8565adbc PS |
244 | MAKEWORD(kim_gdata->resp_buffer[12], |
245 | kim_gdata->resp_buffer[13]); | |
d0088ce1 PS |
246 | chip = (version & 0x7C00) >> 10; |
247 | min_ver = (version & 0x007F); | |
248 | maj_ver = (version & 0x0380) >> 7; | |
249 | ||
250 | if (version & 0x8000) | |
251 | maj_ver |= 0x0008; | |
252 | ||
4dcc2ab3 EBS |
253 | sprintf(bts_scr_name, "ti-connectivity/TIInit_%d.%d.%d.bts", |
254 | chip, maj_ver, min_ver); | |
e2a53282 NJ |
255 | |
256 | /* to be accessed later via sysfs entry */ | |
257 | kim_gdata->version.full = version; | |
258 | kim_gdata->version.chip = chip; | |
259 | kim_gdata->version.maj_ver = maj_ver; | |
260 | kim_gdata->version.min_ver = min_ver; | |
261 | ||
d0088ce1 | 262 | pr_info("%s", bts_scr_name); |
320920cb | 263 | return 0; |
d0088ce1 PS |
264 | } |
265 | ||
27712b39 | 266 | static void skip_change_remote_baud(unsigned char **ptr, long *len) |
ef04d121 PS |
267 | { |
268 | unsigned char *nxt_action, *cur_action; | |
269 | cur_action = *ptr; | |
270 | ||
271 | nxt_action = cur_action + sizeof(struct bts_action) + | |
272 | ((struct bts_action *) cur_action)->size; | |
273 | ||
274 | if (((struct bts_action *) nxt_action)->type != ACTION_WAIT_EVENT) { | |
275 | pr_err("invalid action after change remote baud command"); | |
276 | } else { | |
277 | *ptr = *ptr + sizeof(struct bts_action) + | |
9d031d94 | 278 | ((struct bts_action *)cur_action)->size; |
ef04d121 | 279 | *len = *len - (sizeof(struct bts_action) + |
9d031d94 | 280 | ((struct bts_action *)cur_action)->size); |
ef04d121 PS |
281 | /* warn user on not commenting these in firmware */ |
282 | pr_warn("skipping the wait event of change remote baud"); | |
283 | } | |
284 | } | |
285 | ||
36b5aee4 PS |
286 | /** |
287 | * download_firmware - | |
288 | * internal function which parses through the .bts firmware | |
289 | * script file intreprets SEND, DELAY actions only as of now | |
d0088ce1 | 290 | */ |
38d9df49 | 291 | static long download_firmware(struct kim_data_s *kim_gdata) |
d0088ce1 | 292 | { |
320920cb | 293 | long err = 0; |
d0088ce1 | 294 | long len = 0; |
73f12e8d PS |
295 | unsigned char *ptr = NULL; |
296 | unsigned char *action_ptr = NULL; | |
4dcc2ab3 | 297 | unsigned char bts_scr_name[40] = { 0 }; /* 40 char long bts scr name? */ |
ef04d121 PS |
298 | int wr_room_space; |
299 | int cmd_size; | |
300 | unsigned long timeout; | |
d0088ce1 | 301 | |
38d9df49 | 302 | err = read_local_version(kim_gdata, bts_scr_name); |
320920cb | 303 | if (err != 0) { |
d0088ce1 PS |
304 | pr_err("kim: failed to read local ver"); |
305 | return err; | |
306 | } | |
307 | err = | |
308 | request_firmware(&kim_gdata->fw_entry, bts_scr_name, | |
309 | &kim_gdata->kim_pdev->dev); | |
310 | if (unlikely((err != 0) || (kim_gdata->fw_entry->data == NULL) || | |
311 | (kim_gdata->fw_entry->size == 0))) { | |
312 | pr_err(" request_firmware failed(errno %ld) for %s", err, | |
313 | bts_scr_name); | |
70442664 | 314 | return -EINVAL; |
d0088ce1 PS |
315 | } |
316 | ptr = (void *)kim_gdata->fw_entry->data; | |
317 | len = kim_gdata->fw_entry->size; | |
318 | /* bts_header to remove out magic number and | |
319 | * version | |
320 | */ | |
321 | ptr += sizeof(struct bts_header); | |
322 | len -= sizeof(struct bts_header); | |
323 | ||
324 | while (len > 0 && ptr) { | |
e6d9e64e | 325 | pr_debug(" action size %d, type %d ", |
d0088ce1 PS |
326 | ((struct bts_action *)ptr)->size, |
327 | ((struct bts_action *)ptr)->type); | |
328 | ||
329 | switch (((struct bts_action *)ptr)->type) { | |
330 | case ACTION_SEND_COMMAND: /* action send */ | |
2f81a02c | 331 | pr_debug("S"); |
d0088ce1 PS |
332 | action_ptr = &(((struct bts_action *)ptr)->data[0]); |
333 | if (unlikely | |
334 | (((struct hci_command *)action_ptr)->opcode == | |
335 | 0xFF36)) { | |
336 | /* ignore remote change | |
337 | * baud rate HCI VS command */ | |
ef04d121 | 338 | pr_warn("change remote baud" |
e6d9e64e | 339 | " rate command in firmware"); |
ef04d121 | 340 | skip_change_remote_baud(&ptr, &len); |
d0088ce1 PS |
341 | break; |
342 | } | |
ef04d121 PS |
343 | /* |
344 | * Make sure we have enough free space in uart | |
345 | * tx buffer to write current firmware command | |
346 | */ | |
347 | cmd_size = ((struct bts_action *)ptr)->size; | |
348 | timeout = jiffies + msecs_to_jiffies(CMD_WR_TIME); | |
349 | do { | |
350 | wr_room_space = | |
351 | st_get_uart_wr_room(kim_gdata->core_data); | |
352 | if (wr_room_space < 0) { | |
353 | pr_err("Unable to get free " | |
354 | "space info from uart tx buffer"); | |
355 | release_firmware(kim_gdata->fw_entry); | |
356 | return wr_room_space; | |
357 | } | |
358 | mdelay(1); /* wait 1ms before checking room */ | |
359 | } while ((wr_room_space < cmd_size) && | |
360 | time_before(jiffies, timeout)); | |
361 | ||
362 | /* Timeout happened ? */ | |
363 | if (time_after_eq(jiffies, timeout)) { | |
364 | pr_err("Timeout while waiting for free " | |
365 | "free space in uart tx buffer"); | |
366 | release_firmware(kim_gdata->fw_entry); | |
367 | return -ETIMEDOUT; | |
368 | } | |
2f81a02c PS |
369 | /* reinit completion before sending for the |
370 | * relevant wait | |
371 | */ | |
16735d02 | 372 | reinit_completion(&kim_gdata->kim_rcvd); |
d0088ce1 | 373 | |
ef04d121 PS |
374 | /* |
375 | * Free space found in uart buffer, call st_int_write | |
376 | * to send current firmware command to the uart tx | |
377 | * buffer. | |
378 | */ | |
d0088ce1 PS |
379 | err = st_int_write(kim_gdata->core_data, |
380 | ((struct bts_action_send *)action_ptr)->data, | |
381 | ((struct bts_action *)ptr)->size); | |
382 | if (unlikely(err < 0)) { | |
383 | release_firmware(kim_gdata->fw_entry); | |
70442664 | 384 | return err; |
d0088ce1 | 385 | } |
ef04d121 PS |
386 | /* |
387 | * Check number of bytes written to the uart tx buffer | |
388 | * and requested command write size | |
389 | */ | |
390 | if (err != cmd_size) { | |
391 | pr_err("Number of bytes written to uart " | |
392 | "tx buffer are not matching with " | |
393 | "requested cmd write size"); | |
394 | release_firmware(kim_gdata->fw_entry); | |
395 | return -EIO; | |
396 | } | |
397 | break; | |
398 | case ACTION_WAIT_EVENT: /* wait */ | |
2f81a02c | 399 | pr_debug("W"); |
3f46d81a | 400 | err = wait_for_completion_interruptible_timeout( |
53702358 | 401 | &kim_gdata->kim_rcvd, |
3f46d81a NMG |
402 | msecs_to_jiffies(CMD_RESP_TIME)); |
403 | if (err <= 0) { | |
404 | pr_err("response timeout/signaled during fw download "); | |
d0088ce1 PS |
405 | /* timed out */ |
406 | release_firmware(kim_gdata->fw_entry); | |
3f46d81a | 407 | return err ? -ERESTARTSYS : -ETIMEDOUT; |
d0088ce1 | 408 | } |
16735d02 | 409 | reinit_completion(&kim_gdata->kim_rcvd); |
d0088ce1 PS |
410 | break; |
411 | case ACTION_DELAY: /* sleep */ | |
412 | pr_info("sleep command in scr"); | |
413 | action_ptr = &(((struct bts_action *)ptr)->data[0]); | |
414 | mdelay(((struct bts_action_delay *)action_ptr)->msec); | |
415 | break; | |
416 | } | |
417 | len = | |
418 | len - (sizeof(struct bts_action) + | |
419 | ((struct bts_action *)ptr)->size); | |
420 | ptr = | |
421 | ptr + sizeof(struct bts_action) + | |
422 | ((struct bts_action *)ptr)->size; | |
423 | } | |
424 | /* fw download complete */ | |
425 | release_firmware(kim_gdata->fw_entry); | |
320920cb | 426 | return 0; |
d0088ce1 PS |
427 | } |
428 | ||
429 | /**********************************************************************/ | |
430 | /* functions called from ST core */ | |
d0088ce1 PS |
431 | /* called from ST Core, when REG_IN_PROGRESS (registration in progress) |
432 | * can be because of | |
433 | * 1. response to read local version | |
434 | * 2. during send/recv's of firmware download | |
435 | */ | |
436 | void st_kim_recv(void *disc_data, const unsigned char *data, long count) | |
437 | { | |
38d9df49 PS |
438 | struct st_data_s *st_gdata = (struct st_data_s *)disc_data; |
439 | struct kim_data_s *kim_gdata = st_gdata->kim_data; | |
440 | ||
8565adbc PS |
441 | /* proceed to gather all data and distinguish read fw version response |
442 | * from other fw responses when data gathering is complete | |
443 | */ | |
444 | kim_int_recv(kim_gdata, data, count); | |
d0088ce1 PS |
445 | return; |
446 | } | |
447 | ||
448 | /* to signal completion of line discipline installation | |
449 | * called from ST Core, upon tty_open | |
450 | */ | |
38d9df49 | 451 | void st_kim_complete(void *kim_data) |
d0088ce1 | 452 | { |
38d9df49 | 453 | struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; |
d0088ce1 PS |
454 | complete(&kim_gdata->ldisc_installed); |
455 | } | |
456 | ||
36b5aee4 PS |
457 | /** |
458 | * st_kim_start - called from ST Core upon 1st registration | |
459 | * This involves toggling the chip enable gpio, reading | |
460 | * the firmware version from chip, forming the fw file name | |
461 | * based on the chip version, requesting the fw, parsing it | |
462 | * and perform download(send/recv). | |
463 | */ | |
38d9df49 | 464 | long st_kim_start(void *kim_data) |
d0088ce1 | 465 | { |
320920cb | 466 | long err = 0; |
d0088ce1 | 467 | long retry = POR_RETRY_COUNT; |
0d7c5f25 | 468 | struct ti_st_plat_data *pdata; |
38d9df49 PS |
469 | struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; |
470 | ||
d0088ce1 | 471 | pr_info(" %s", __func__); |
46d0d333 GJ |
472 | if (kim_gdata->kim_pdev->dev.of_node) { |
473 | pr_debug("use device tree data"); | |
474 | pdata = dt_pdata; | |
475 | } else { | |
476 | pdata = kim_gdata->kim_pdev->dev.platform_data; | |
477 | } | |
d0088ce1 PS |
478 | |
479 | do { | |
0d7c5f25 PS |
480 | /* platform specific enabling code here */ |
481 | if (pdata->chip_enable) | |
482 | pdata->chip_enable(kim_gdata); | |
483 | ||
a7e2ca17 LC |
484 | /* Configure BT nShutdown to HIGH state */ |
485 | gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); | |
486 | mdelay(5); /* FIXME: a proper toggle */ | |
487 | gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); | |
488 | mdelay(100); | |
d0088ce1 | 489 | /* re-initialize the completion */ |
16735d02 | 490 | reinit_completion(&kim_gdata->ldisc_installed); |
ec60d0ad PS |
491 | /* send notification to UIM */ |
492 | kim_gdata->ldisc_install = 1; | |
493 | pr_info("ldisc_install = 1"); | |
494 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, | |
495 | NULL, "install"); | |
d0088ce1 | 496 | /* wait for ldisc to be installed */ |
53702358 PS |
497 | err = wait_for_completion_interruptible_timeout( |
498 | &kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME)); | |
18ccecf9 PS |
499 | if (!err) { |
500 | /* ldisc installation timeout, | |
501 | * flush uart, power cycle BT_EN */ | |
502 | pr_err("ldisc installation timeout"); | |
503 | err = st_kim_stop(kim_gdata); | |
d0088ce1 PS |
504 | continue; |
505 | } else { | |
506 | /* ldisc installed now */ | |
18ccecf9 | 507 | pr_info("line discipline installed"); |
38d9df49 | 508 | err = download_firmware(kim_gdata); |
320920cb | 509 | if (err != 0) { |
18ccecf9 PS |
510 | /* ldisc installed but fw download failed, |
511 | * flush uart & power cycle BT_EN */ | |
d0088ce1 | 512 | pr_err("download firmware failed"); |
18ccecf9 | 513 | err = st_kim_stop(kim_gdata); |
d0088ce1 PS |
514 | continue; |
515 | } else { /* on success don't retry */ | |
516 | break; | |
517 | } | |
518 | } | |
519 | } while (retry--); | |
520 | return err; | |
521 | } | |
522 | ||
36b5aee4 | 523 | /** |
18ccecf9 PS |
524 | * st_kim_stop - stop communication with chip. |
525 | * This can be called from ST Core/KIM, on the- | |
526 | * (a) last un-register when chip need not be powered there-after, | |
527 | * (b) upon failure to either install ldisc or download firmware. | |
528 | * The function is responsible to (a) notify UIM about un-installation, | |
529 | * (b) flush UART if the ldisc was installed. | |
a7e2ca17 LC |
530 | * (c) reset BT_EN - pull down nshutdown at the end. |
531 | * (d) invoke platform's chip disabling routine. | |
36b5aee4 | 532 | */ |
38d9df49 | 533 | long st_kim_stop(void *kim_data) |
d0088ce1 | 534 | { |
320920cb | 535 | long err = 0; |
38d9df49 | 536 | struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; |
46d0d333 | 537 | struct ti_st_plat_data *pdata; |
18ccecf9 | 538 | struct tty_struct *tty = kim_gdata->core_data->tty; |
d0088ce1 | 539 | |
16735d02 | 540 | reinit_completion(&kim_gdata->ldisc_installed); |
ec60d0ad | 541 | |
46d0d333 GJ |
542 | if (kim_gdata->kim_pdev->dev.of_node) { |
543 | pr_debug("use device tree data"); | |
544 | pdata = dt_pdata; | |
545 | } else | |
546 | pdata = kim_gdata->kim_pdev->dev.platform_data; | |
547 | ||
548 | ||
18ccecf9 PS |
549 | if (tty) { /* can be called before ldisc is installed */ |
550 | /* Flush any pending characters in the driver and discipline. */ | |
551 | tty_ldisc_flush(tty); | |
552 | tty_driver_flush_buffer(tty); | |
18ccecf9 | 553 | } |
ec60d0ad PS |
554 | |
555 | /* send uninstall notification to UIM */ | |
556 | pr_info("ldisc_install = 0"); | |
557 | kim_gdata->ldisc_install = 0; | |
558 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install"); | |
d0088ce1 PS |
559 | |
560 | /* wait for ldisc to be un-installed */ | |
53702358 PS |
561 | err = wait_for_completion_interruptible_timeout( |
562 | &kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME)); | |
d0088ce1 PS |
563 | if (!err) { /* timeout */ |
564 | pr_err(" timed out waiting for ldisc to be un-installed"); | |
b64365a5 | 565 | err = -ETIMEDOUT; |
d0088ce1 PS |
566 | } |
567 | ||
a7e2ca17 LC |
568 | /* By default configure BT nShutdown to LOW state */ |
569 | gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); | |
570 | mdelay(1); | |
571 | gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); | |
572 | mdelay(1); | |
573 | gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); | |
574 | ||
0d7c5f25 PS |
575 | /* platform specific disable */ |
576 | if (pdata->chip_disable) | |
577 | pdata->chip_disable(kim_gdata); | |
d0088ce1 PS |
578 | return err; |
579 | } | |
580 | ||
581 | /**********************************************************************/ | |
582 | /* functions called from subsystems */ | |
c1afac15 | 583 | /* called when debugfs entry is read from */ |
e2a53282 | 584 | |
c1afac15 | 585 | static int show_version(struct seq_file *s, void *unused) |
e2a53282 | 586 | { |
c1afac15 PS |
587 | struct kim_data_s *kim_gdata = (struct kim_data_s *)s->private; |
588 | seq_printf(s, "%04X %d.%d.%d\n", kim_gdata->version.full, | |
e2a53282 NJ |
589 | kim_gdata->version.chip, kim_gdata->version.maj_ver, |
590 | kim_gdata->version.min_ver); | |
c1afac15 | 591 | return 0; |
d0088ce1 PS |
592 | } |
593 | ||
c1afac15 | 594 | static int show_list(struct seq_file *s, void *unused) |
d0088ce1 | 595 | { |
c1afac15 PS |
596 | struct kim_data_s *kim_gdata = (struct kim_data_s *)s->private; |
597 | kim_st_list_protocols(kim_gdata->core_data, s); | |
598 | return 0; | |
d0088ce1 PS |
599 | } |
600 | ||
ec60d0ad PS |
601 | static ssize_t show_install(struct device *dev, |
602 | struct device_attribute *attr, char *buf) | |
d0088ce1 | 603 | { |
ec60d0ad PS |
604 | struct kim_data_s *kim_data = dev_get_drvdata(dev); |
605 | return sprintf(buf, "%d\n", kim_data->ldisc_install); | |
606 | } | |
d0088ce1 | 607 | |
933aae54 PS |
608 | #ifdef DEBUG |
609 | static ssize_t store_dev_name(struct device *dev, | |
610 | struct device_attribute *attr, const char *buf, size_t count) | |
611 | { | |
612 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | |
613 | pr_debug("storing dev name >%s<", buf); | |
614 | strncpy(kim_data->dev_name, buf, count); | |
615 | pr_debug("stored dev name >%s<", kim_data->dev_name); | |
616 | return count; | |
617 | } | |
618 | ||
619 | static ssize_t store_baud_rate(struct device *dev, | |
620 | struct device_attribute *attr, const char *buf, size_t count) | |
621 | { | |
622 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | |
623 | pr_debug("storing baud rate >%s<", buf); | |
624 | sscanf(buf, "%ld", &kim_data->baud_rate); | |
625 | pr_debug("stored baud rate >%ld<", kim_data->baud_rate); | |
626 | return count; | |
627 | } | |
628 | #endif /* if DEBUG */ | |
629 | ||
ec60d0ad PS |
630 | static ssize_t show_dev_name(struct device *dev, |
631 | struct device_attribute *attr, char *buf) | |
632 | { | |
633 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | |
634 | return sprintf(buf, "%s\n", kim_data->dev_name); | |
635 | } | |
636 | ||
637 | static ssize_t show_baud_rate(struct device *dev, | |
638 | struct device_attribute *attr, char *buf) | |
639 | { | |
640 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | |
641 | return sprintf(buf, "%ld\n", kim_data->baud_rate); | |
642 | } | |
643 | ||
644 | static ssize_t show_flow_cntrl(struct device *dev, | |
645 | struct device_attribute *attr, char *buf) | |
646 | { | |
647 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | |
648 | return sprintf(buf, "%d\n", kim_data->flow_cntrl); | |
d0088ce1 PS |
649 | } |
650 | ||
ec60d0ad PS |
651 | /* structures specific for sysfs entries */ |
652 | static struct kobj_attribute ldisc_install = | |
653 | __ATTR(install, 0444, (void *)show_install, NULL); | |
654 | ||
655 | static struct kobj_attribute uart_dev_name = | |
933aae54 PS |
656 | #ifdef DEBUG /* TODO: move this to debug-fs if possible */ |
657 | __ATTR(dev_name, 0644, (void *)show_dev_name, (void *)store_dev_name); | |
658 | #else | |
ec60d0ad | 659 | __ATTR(dev_name, 0444, (void *)show_dev_name, NULL); |
933aae54 | 660 | #endif |
ec60d0ad PS |
661 | |
662 | static struct kobj_attribute uart_baud_rate = | |
933aae54 PS |
663 | #ifdef DEBUG /* TODO: move to debugfs */ |
664 | __ATTR(baud_rate, 0644, (void *)show_baud_rate, (void *)store_baud_rate); | |
665 | #else | |
ec60d0ad | 666 | __ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL); |
933aae54 | 667 | #endif |
ec60d0ad PS |
668 | |
669 | static struct kobj_attribute uart_flow_cntrl = | |
670 | __ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL); | |
671 | ||
672 | static struct attribute *uim_attrs[] = { | |
673 | &ldisc_install.attr, | |
674 | &uart_dev_name.attr, | |
675 | &uart_baud_rate.attr, | |
676 | &uart_flow_cntrl.attr, | |
677 | NULL, | |
678 | }; | |
679 | ||
680 | static struct attribute_group uim_attr_grp = { | |
681 | .attrs = uim_attrs, | |
682 | }; | |
683 | ||
36b5aee4 PS |
684 | /** |
685 | * st_kim_ref - reference the core's data | |
686 | * This references the per-ST platform device in the arch/xx/ | |
687 | * board-xx.c file. | |
688 | * This would enable multiple such platform devices to exist | |
689 | * on a given platform | |
690 | */ | |
dbd3a870 | 691 | void st_kim_ref(struct st_data_s **core_data, int id) |
d0088ce1 | 692 | { |
38d9df49 PS |
693 | struct platform_device *pdev; |
694 | struct kim_data_s *kim_gdata; | |
695 | /* get kim_gdata reference from platform device */ | |
dbd3a870 | 696 | pdev = st_get_plat_device(id); |
868eba8e GJ |
697 | if (!pdev) |
698 | goto err; | |
9093ca88 | 699 | kim_gdata = platform_get_drvdata(pdev); |
868eba8e GJ |
700 | if (!kim_gdata) |
701 | goto err; | |
702 | ||
d0088ce1 | 703 | *core_data = kim_gdata->core_data; |
868eba8e GJ |
704 | return; |
705 | err: | |
706 | *core_data = NULL; | |
d0088ce1 PS |
707 | } |
708 | ||
c1afac15 PS |
709 | static int kim_version_open(struct inode *i, struct file *f) |
710 | { | |
711 | return single_open(f, show_version, i->i_private); | |
712 | } | |
713 | ||
714 | static int kim_list_open(struct inode *i, struct file *f) | |
715 | { | |
716 | return single_open(f, show_list, i->i_private); | |
717 | } | |
718 | ||
719 | static const struct file_operations version_debugfs_fops = { | |
720 | /* version info */ | |
721 | .open = kim_version_open, | |
722 | .read = seq_read, | |
723 | .llseek = seq_lseek, | |
724 | .release = single_release, | |
725 | }; | |
726 | static const struct file_operations list_debugfs_fops = { | |
727 | /* protocols info */ | |
728 | .open = kim_list_open, | |
729 | .read = seq_read, | |
730 | .llseek = seq_lseek, | |
731 | .release = single_release, | |
732 | }; | |
733 | ||
d0088ce1 PS |
734 | /**********************************************************************/ |
735 | /* functions called from platform device driver subsystem | |
736 | * need to have a relevant platform device entry in the platform's | |
737 | * board-*.c file | |
738 | */ | |
739 | ||
46d0d333 GJ |
740 | static const struct of_device_id kim_of_match[] = { |
741 | { | |
742 | .compatible = "kim", | |
743 | }, | |
744 | {} | |
745 | }; | |
746 | MODULE_DEVICE_TABLE(of, kim_of_match); | |
747 | ||
748 | static struct ti_st_plat_data *get_platform_data(struct device *dev) | |
749 | { | |
750 | struct device_node *np = dev->of_node; | |
751 | const u32 *dt_property; | |
752 | int len; | |
753 | ||
754 | dt_pdata = kzalloc(sizeof(*dt_pdata), GFP_KERNEL); | |
755 | ||
756 | if (!dt_pdata) | |
757 | pr_err("Can't allocate device_tree platform data\n"); | |
758 | ||
759 | dt_property = of_get_property(np, "dev_name", &len); | |
760 | if (dt_property) | |
761 | memcpy(&dt_pdata->dev_name, dt_property, len); | |
762 | of_property_read_u32(np, "nshutdown_gpio", | |
763 | (u32 *)&dt_pdata->nshutdown_gpio); | |
764 | of_property_read_u32(np, "flow_cntrl", (u32 *)&dt_pdata->flow_cntrl); | |
765 | of_property_read_u32(np, "baud_rate", (u32 *)&dt_pdata->baud_rate); | |
766 | ||
767 | return dt_pdata; | |
768 | } | |
769 | ||
27712b39 | 770 | static struct dentry *kim_debugfs_dir; |
d0088ce1 PS |
771 | static int kim_probe(struct platform_device *pdev) |
772 | { | |
38d9df49 | 773 | struct kim_data_s *kim_gdata; |
46d0d333 | 774 | struct ti_st_plat_data *pdata; |
b2997387 | 775 | int err; |
38d9df49 | 776 | |
46d0d333 GJ |
777 | if (pdev->dev.of_node) |
778 | pdata = get_platform_data(&pdev->dev); | |
779 | else | |
780 | pdata = pdev->dev.platform_data; | |
781 | ||
782 | if (pdata == NULL) { | |
783 | dev_err(&pdev->dev, "Platform Data is missing\n"); | |
784 | return -ENXIO; | |
785 | } | |
786 | ||
dfb7ef7d PS |
787 | if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { |
788 | /* multiple devices could exist */ | |
789 | st_kim_devices[pdev->id] = pdev; | |
790 | } else { | |
25985edc | 791 | /* platform's sure about existence of 1 device */ |
dfb7ef7d PS |
792 | st_kim_devices[0] = pdev; |
793 | } | |
794 | ||
38d9df49 PS |
795 | kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC); |
796 | if (!kim_gdata) { | |
797 | pr_err("no mem to allocate"); | |
798 | return -ENOMEM; | |
799 | } | |
9093ca88 | 800 | platform_set_drvdata(pdev, kim_gdata); |
d0088ce1 | 801 | |
b2997387 MK |
802 | err = st_core_init(&kim_gdata->core_data); |
803 | if (err != 0) { | |
d0088ce1 | 804 | pr_err(" ST core init failed"); |
b2997387 MK |
805 | err = -EIO; |
806 | goto err_core_init; | |
d0088ce1 | 807 | } |
38d9df49 PS |
808 | /* refer to itself */ |
809 | kim_gdata->core_data->kim_data = kim_gdata; | |
d0088ce1 | 810 | |
a7e2ca17 LC |
811 | /* Claim the chip enable nShutdown gpio from the system */ |
812 | kim_gdata->nshutdown = pdata->nshutdown_gpio; | |
813 | err = gpio_request(kim_gdata->nshutdown, "kim"); | |
814 | if (unlikely(err)) { | |
815 | pr_err(" gpio %ld request failed ", kim_gdata->nshutdown); | |
816 | return err; | |
817 | } | |
818 | ||
819 | /* Configure nShutdown GPIO as output=0 */ | |
820 | err = gpio_direction_output(kim_gdata->nshutdown, 0); | |
821 | if (unlikely(err)) { | |
822 | pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown); | |
823 | return err; | |
824 | } | |
d0088ce1 PS |
825 | /* get reference of pdev for request_firmware |
826 | */ | |
827 | kim_gdata->kim_pdev = pdev; | |
828 | init_completion(&kim_gdata->kim_rcvd); | |
829 | init_completion(&kim_gdata->ldisc_installed); | |
b38fc2d9 | 830 | |
b2997387 MK |
831 | err = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); |
832 | if (err) { | |
ec60d0ad | 833 | pr_err("failed to create sysfs entries"); |
b2997387 | 834 | goto err_sysfs_group; |
d0088ce1 | 835 | } |
e2a53282 | 836 | |
ec60d0ad PS |
837 | /* copying platform data */ |
838 | strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN); | |
839 | kim_gdata->flow_cntrl = pdata->flow_cntrl; | |
840 | kim_gdata->baud_rate = pdata->baud_rate; | |
841 | pr_info("sysfs entries created\n"); | |
842 | ||
c1afac15 | 843 | kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); |
3768528a | 844 | if (!kim_debugfs_dir) { |
c1afac15 | 845 | pr_err(" debugfs entries creation failed "); |
c6ec0fb4 | 846 | return 0; |
e2a53282 | 847 | } |
c1afac15 PS |
848 | |
849 | debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, | |
850 | kim_gdata, &version_debugfs_fops); | |
851 | debugfs_create_file("protocols", S_IRUGO, kim_debugfs_dir, | |
852 | kim_gdata, &list_debugfs_fops); | |
320920cb | 853 | return 0; |
b2997387 | 854 | |
b2997387 MK |
855 | err_sysfs_group: |
856 | st_core_exit(kim_gdata->core_data); | |
857 | ||
858 | err_core_init: | |
859 | kfree(kim_gdata); | |
860 | ||
861 | return err; | |
d0088ce1 PS |
862 | } |
863 | ||
864 | static int kim_remove(struct platform_device *pdev) | |
865 | { | |
a7e2ca17 | 866 | /* free the GPIOs requested */ |
46d0d333 | 867 | struct ti_st_plat_data *pdata; |
38d9df49 PS |
868 | struct kim_data_s *kim_gdata; |
869 | ||
46d0d333 GJ |
870 | if (pdev->dev.of_node) { |
871 | pr_debug("use device tree data"); | |
872 | pdata = dt_pdata; | |
873 | } else { | |
874 | pdata = pdev->dev.platform_data; | |
875 | } | |
876 | ||
9093ca88 | 877 | kim_gdata = platform_get_drvdata(pdev); |
d0088ce1 | 878 | |
a7e2ca17 LC |
879 | /* Free the Bluetooth/FM/GPIO |
880 | * nShutdown gpio from the system | |
881 | */ | |
882 | gpio_free(pdata->nshutdown_gpio); | |
883 | pr_info("nshutdown GPIO Freed"); | |
884 | ||
781a7395 | 885 | debugfs_remove_recursive(kim_debugfs_dir); |
ec60d0ad | 886 | sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); |
781a7395 PS |
887 | pr_info("sysfs entries removed"); |
888 | ||
d0088ce1 PS |
889 | kim_gdata->kim_pdev = NULL; |
890 | st_core_exit(kim_gdata->core_data); | |
38d9df49 PS |
891 | |
892 | kfree(kim_gdata); | |
893 | kim_gdata = NULL; | |
46d0d333 GJ |
894 | kfree(dt_pdata); |
895 | dt_pdata = NULL; | |
896 | ||
320920cb | 897 | return 0; |
d0088ce1 PS |
898 | } |
899 | ||
27712b39 | 900 | static int kim_suspend(struct platform_device *pdev, pm_message_t state) |
ec60d0ad | 901 | { |
46d0d333 GJ |
902 | struct ti_st_plat_data *pdata; |
903 | ||
904 | if (pdev->dev.of_node) { | |
905 | pr_debug("use device tree data"); | |
906 | pdata = dt_pdata; | |
907 | } else { | |
908 | pdata = pdev->dev.platform_data; | |
909 | } | |
ec60d0ad PS |
910 | |
911 | if (pdata->suspend) | |
912 | return pdata->suspend(pdev, state); | |
913 | ||
4b4aa3ab | 914 | return 0; |
ec60d0ad PS |
915 | } |
916 | ||
27712b39 | 917 | static int kim_resume(struct platform_device *pdev) |
ec60d0ad | 918 | { |
46d0d333 GJ |
919 | struct ti_st_plat_data *pdata; |
920 | ||
921 | if (pdev->dev.of_node) { | |
922 | pr_debug("use device tree data"); | |
923 | pdata = dt_pdata; | |
924 | } else { | |
925 | pdata = pdev->dev.platform_data; | |
926 | } | |
ec60d0ad PS |
927 | |
928 | if (pdata->resume) | |
929 | return pdata->resume(pdev); | |
930 | ||
4b4aa3ab | 931 | return 0; |
ec60d0ad PS |
932 | } |
933 | ||
d0088ce1 PS |
934 | /**********************************************************************/ |
935 | /* entry point for ST KIM module, called in from ST Core */ | |
ec60d0ad PS |
936 | static struct platform_driver kim_platform_driver = { |
937 | .probe = kim_probe, | |
938 | .remove = kim_remove, | |
939 | .suspend = kim_suspend, | |
940 | .resume = kim_resume, | |
941 | .driver = { | |
942 | .name = "kim", | |
46d0d333 GJ |
943 | .owner = THIS_MODULE, |
944 | .of_match_table = of_match_ptr(kim_of_match), | |
ec60d0ad PS |
945 | }, |
946 | }; | |
d0088ce1 | 947 | |
b00e126f | 948 | module_platform_driver(kim_platform_driver); |
d0088ce1 | 949 | |
d0088ce1 PS |
950 | MODULE_AUTHOR("Pavan Savoy <pavan_savoy@ti.com>"); |
951 | MODULE_DESCRIPTION("Shared Transport Driver for TI BT/FM/GPS combo chips "); | |
952 | MODULE_LICENSE("GPL"); |