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_debug("%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_debug("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_debug("wake indication recvd"); 125 ll_device_want_to_wakeup(st_data); 126 break; 127 case LL_WAKE_UP_ACK: /* wake ack */ 128 pr_debug("wake ack rcvd"); 129 st_data->ll_state = ST_LL_AWAKE; 130 break; 131 default: 132 pr_err(" unknown input/state "); 133 return -EINVAL; 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 } 151