diff options
Diffstat (limited to 'drivers/misc/ti-st/st_ll.c')
-rw-r--r-- | drivers/misc/ti-st/st_ll.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c new file mode 100644 index 000000000000..2bda8dea15b0 --- /dev/null +++ b/drivers/misc/ti-st/st_ll.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * Shared Transport driver | ||
3 | * HCI-LL module responsible for TI proprietary HCI_LL protocol | ||
4 | * Copyright (C) 2009-2010 Texas Instruments | ||
5 | * Author: Pavan Savoy <pavan_savoy@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #define pr_fmt(fmt) "(stll) :" fmt | ||
23 | #include <linux/skbuff.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/ti_wilink_st.h> | ||
26 | |||
27 | /**********************************************************************/ | ||
28 | /* internal functions */ | ||
29 | static void send_ll_cmd(struct st_data_s *st_data, | ||
30 | unsigned char cmd) | ||
31 | { | ||
32 | |||
33 | pr_info("%s: writing %x", __func__, cmd); | ||
34 | st_int_write(st_data, &cmd, 1); | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | static void ll_device_want_to_sleep(struct st_data_s *st_data) | ||
39 | { | ||
40 | pr_debug("%s", __func__); | ||
41 | /* sanity check */ | ||
42 | if (st_data->ll_state != ST_LL_AWAKE) | ||
43 | pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND" | ||
44 | "in state %ld", st_data->ll_state); | ||
45 | |||
46 | send_ll_cmd(st_data, LL_SLEEP_ACK); | ||
47 | /* update state */ | ||
48 | st_data->ll_state = ST_LL_ASLEEP; | ||
49 | } | ||
50 | |||
51 | static void ll_device_want_to_wakeup(struct st_data_s *st_data) | ||
52 | { | ||
53 | /* diff actions in diff states */ | ||
54 | switch (st_data->ll_state) { | ||
55 | case ST_LL_ASLEEP: | ||
56 | send_ll_cmd(st_data, LL_WAKE_UP_ACK); /* send wake_ack */ | ||
57 | break; | ||
58 | case ST_LL_ASLEEP_TO_AWAKE: | ||
59 | /* duplicate wake_ind */ | ||
60 | pr_err("duplicate wake_ind while waiting for Wake ack"); | ||
61 | break; | ||
62 | case ST_LL_AWAKE: | ||
63 | /* duplicate wake_ind */ | ||
64 | pr_err("duplicate wake_ind already AWAKE"); | ||
65 | break; | ||
66 | case ST_LL_AWAKE_TO_ASLEEP: | ||
67 | /* duplicate wake_ind */ | ||
68 | pr_err("duplicate wake_ind"); | ||
69 | break; | ||
70 | } | ||
71 | /* update state */ | ||
72 | st_data->ll_state = ST_LL_AWAKE; | ||
73 | } | ||
74 | |||
75 | /**********************************************************************/ | ||
76 | /* functions invoked by ST Core */ | ||
77 | |||
78 | /* called when ST Core wants to | ||
79 | * enable ST LL */ | ||
80 | void st_ll_enable(struct st_data_s *ll) | ||
81 | { | ||
82 | ll->ll_state = ST_LL_AWAKE; | ||
83 | } | ||
84 | |||
85 | /* called when ST Core /local module wants to | ||
86 | * disable ST LL */ | ||
87 | void st_ll_disable(struct st_data_s *ll) | ||
88 | { | ||
89 | ll->ll_state = ST_LL_INVALID; | ||
90 | } | ||
91 | |||
92 | /* called when ST Core wants to update the state */ | ||
93 | void st_ll_wakeup(struct st_data_s *ll) | ||
94 | { | ||
95 | if (likely(ll->ll_state != ST_LL_AWAKE)) { | ||
96 | send_ll_cmd(ll, LL_WAKE_UP_IND); /* WAKE_IND */ | ||
97 | ll->ll_state = ST_LL_ASLEEP_TO_AWAKE; | ||
98 | } else { | ||
99 | /* don't send the duplicate wake_indication */ | ||
100 | pr_err(" Chip already AWAKE "); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /* called when ST Core wants the state */ | ||
105 | unsigned long st_ll_getstate(struct st_data_s *ll) | ||
106 | { | ||
107 | pr_debug(" returning state %ld", ll->ll_state); | ||
108 | return ll->ll_state; | ||
109 | } | ||
110 | |||
111 | /* called from ST Core, when a PM related packet arrives */ | ||
112 | unsigned long st_ll_sleep_state(struct st_data_s *st_data, | ||
113 | unsigned char cmd) | ||
114 | { | ||
115 | switch (cmd) { | ||
116 | case LL_SLEEP_IND: /* sleep ind */ | ||
117 | pr_info("sleep indication recvd"); | ||
118 | ll_device_want_to_sleep(st_data); | ||
119 | break; | ||
120 | case LL_SLEEP_ACK: /* sleep ack */ | ||
121 | pr_err("sleep ack rcvd: host shouldn't"); | ||
122 | break; | ||
123 | case LL_WAKE_UP_IND: /* wake ind */ | ||
124 | pr_info("wake indication recvd"); | ||
125 | ll_device_want_to_wakeup(st_data); | ||
126 | break; | ||
127 | case LL_WAKE_UP_ACK: /* wake ack */ | ||
128 | pr_info("wake ack rcvd"); | ||
129 | st_data->ll_state = ST_LL_AWAKE; | ||
130 | break; | ||
131 | default: | ||
132 | pr_err(" unknown input/state "); | ||
133 | return -1; | ||
134 | } | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | /* Called from ST CORE to initialize ST LL */ | ||
139 | long st_ll_init(struct st_data_s *ll) | ||
140 | { | ||
141 | /* set state to invalid */ | ||
142 | ll->ll_state = ST_LL_INVALID; | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | /* Called from ST CORE to de-initialize ST LL */ | ||
147 | long st_ll_deinit(struct st_data_s *ll) | ||
148 | { | ||
149 | return 0; | ||
150 | } | ||