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