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/platform_device.h> 26 #include <linux/ti_wilink_st.h> 27 28 /**********************************************************************/ 29 /* internal functions */ 30 static void send_ll_cmd(struct st_data_s *st_data, 31 unsigned char cmd) 32 { 33 34 pr_debug("%s: writing %x", __func__, cmd); 35 st_int_write(st_data, &cmd, 1); 36 return; 37 } 38 39 static void ll_device_want_to_sleep(struct st_data_s *st_data) 40 { 41 struct kim_data_s *kim_data; 42 struct ti_st_plat_data *pdata; 43 44 pr_debug("%s", __func__); 45 /* sanity check */ 46 if (st_data->ll_state != ST_LL_AWAKE) 47 pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND" 48 "in state %ld", st_data->ll_state); 49 50 send_ll_cmd(st_data, LL_SLEEP_ACK); 51 /* update state */ 52 st_data->ll_state = ST_LL_ASLEEP; 53 54 /* communicate to platform about chip asleep */ 55 kim_data = st_data->kim_data; 56 pdata = kim_data->kim_pdev->dev.platform_data; 57 if (pdata->chip_asleep) 58 pdata->chip_asleep(NULL); 59 } 60 61 static void ll_device_want_to_wakeup(struct st_data_s *st_data) 62 { 63 struct kim_data_s *kim_data; 64 struct ti_st_plat_data *pdata; 65 66 /* diff actions in diff states */ 67 switch (st_data->ll_state) { 68 case ST_LL_ASLEEP: 69 send_ll_cmd(st_data, LL_WAKE_UP_ACK); /* send wake_ack */ 70 break; 71 case ST_LL_ASLEEP_TO_AWAKE: 72 /* duplicate wake_ind */ 73 pr_err("duplicate wake_ind while waiting for Wake ack"); 74 break; 75 case ST_LL_AWAKE: 76 /* duplicate wake_ind */ 77 pr_err("duplicate wake_ind already AWAKE"); 78 break; 79 case ST_LL_AWAKE_TO_ASLEEP: 80 /* duplicate wake_ind */ 81 pr_err("duplicate wake_ind"); 82 break; 83 } 84 /* update state */ 85 st_data->ll_state = ST_LL_AWAKE; 86 87 /* communicate to platform about chip wakeup */ 88 kim_data = st_data->kim_data; 89 pdata = kim_data->kim_pdev->dev.platform_data; 90 if (pdata->chip_awake) 91 pdata->chip_awake(NULL); 92 } 93 94 /**********************************************************************/ 95 /* functions invoked by ST Core */ 96 97 /* called when ST Core wants to 98 * enable ST LL */ 99 void st_ll_enable(struct st_data_s *ll) 100 { 101 ll->ll_state = ST_LL_AWAKE; 102 } 103 104 /* called when ST Core /local module wants to 105 * disable ST LL */ 106 void st_ll_disable(struct st_data_s *ll) 107 { 108 ll->ll_state = ST_LL_INVALID; 109 } 110 111 /* called when ST Core wants to update the state */ 112 void st_ll_wakeup(struct st_data_s *ll) 113 { 114 if (likely(ll->ll_state != ST_LL_AWAKE)) { 115 send_ll_cmd(ll, LL_WAKE_UP_IND); /* WAKE_IND */ 116 ll->ll_state = ST_LL_ASLEEP_TO_AWAKE; 117 } else { 118 /* don't send the duplicate wake_indication */ 119 pr_err(" Chip already AWAKE "); 120 } 121 } 122 123 /* called when ST Core wants the state */ 124 unsigned long st_ll_getstate(struct st_data_s *ll) 125 { 126 pr_debug(" returning state %ld", ll->ll_state); 127 return ll->ll_state; 128 } 129 130 /* called from ST Core, when a PM related packet arrives */ 131 unsigned long st_ll_sleep_state(struct st_data_s *st_data, 132 unsigned char cmd) 133 { 134 switch (cmd) { 135 case LL_SLEEP_IND: /* sleep ind */ 136 pr_debug("sleep indication recvd"); 137 ll_device_want_to_sleep(st_data); 138 break; 139 case LL_SLEEP_ACK: /* sleep ack */ 140 pr_err("sleep ack rcvd: host shouldn't"); 141 break; 142 case LL_WAKE_UP_IND: /* wake ind */ 143 pr_debug("wake indication recvd"); 144 ll_device_want_to_wakeup(st_data); 145 break; 146 case LL_WAKE_UP_ACK: /* wake ack */ 147 pr_debug("wake ack rcvd"); 148 st_data->ll_state = ST_LL_AWAKE; 149 break; 150 default: 151 pr_err(" unknown input/state "); 152 return -EINVAL; 153 } 154 return 0; 155 } 156 157 /* Called from ST CORE to initialize ST LL */ 158 long st_ll_init(struct st_data_s *ll) 159 { 160 /* set state to invalid */ 161 ll->ll_state = ST_LL_INVALID; 162 return 0; 163 } 164 165 /* Called from ST CORE to de-initialize ST LL */ 166 long st_ll_deinit(struct st_data_s *ll) 167 { 168 return 0; 169 } 170