/*1* Shared Transport driver2* HCI-LL module responsible for TI proprietary HCI_LL protocol3* Copyright (C) 2009-2010 Texas Instruments4* Author: Pavan Savoy <[email protected]>5*6* This program is free software; you can redistribute it and/or modify7* it under the terms of the GNU General Public License version 2 as8* published by the Free Software Foundation.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*19*/2021#define pr_fmt(fmt) "(stll) :" fmt22#include <linux/skbuff.h>23#include <linux/module.h>24#include <linux/ti_wilink_st.h>2526/**********************************************************************/27/* internal functions */28static void send_ll_cmd(struct st_data_s *st_data,29unsigned char cmd)30{3132pr_debug("%s: writing %x", __func__, cmd);33st_int_write(st_data, &cmd, 1);34return;35}3637static void ll_device_want_to_sleep(struct st_data_s *st_data)38{39pr_debug("%s", __func__);40/* sanity check */41if (st_data->ll_state != ST_LL_AWAKE)42pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND"43"in state %ld", st_data->ll_state);4445send_ll_cmd(st_data, LL_SLEEP_ACK);46/* update state */47st_data->ll_state = ST_LL_ASLEEP;48}4950static void ll_device_want_to_wakeup(struct st_data_s *st_data)51{52/* diff actions in diff states */53switch (st_data->ll_state) {54case ST_LL_ASLEEP:55send_ll_cmd(st_data, LL_WAKE_UP_ACK); /* send wake_ack */56break;57case ST_LL_ASLEEP_TO_AWAKE:58/* duplicate wake_ind */59pr_err("duplicate wake_ind while waiting for Wake ack");60break;61case ST_LL_AWAKE:62/* duplicate wake_ind */63pr_err("duplicate wake_ind already AWAKE");64break;65case ST_LL_AWAKE_TO_ASLEEP:66/* duplicate wake_ind */67pr_err("duplicate wake_ind");68break;69}70/* update state */71st_data->ll_state = ST_LL_AWAKE;72}7374/**********************************************************************/75/* functions invoked by ST Core */7677/* called when ST Core wants to78* enable ST LL */79void st_ll_enable(struct st_data_s *ll)80{81ll->ll_state = ST_LL_AWAKE;82}8384/* called when ST Core /local module wants to85* disable ST LL */86void st_ll_disable(struct st_data_s *ll)87{88ll->ll_state = ST_LL_INVALID;89}9091/* called when ST Core wants to update the state */92void st_ll_wakeup(struct st_data_s *ll)93{94if (likely(ll->ll_state != ST_LL_AWAKE)) {95send_ll_cmd(ll, LL_WAKE_UP_IND); /* WAKE_IND */96ll->ll_state = ST_LL_ASLEEP_TO_AWAKE;97} else {98/* don't send the duplicate wake_indication */99pr_err(" Chip already AWAKE ");100}101}102103/* called when ST Core wants the state */104unsigned long st_ll_getstate(struct st_data_s *ll)105{106pr_debug(" returning state %ld", ll->ll_state);107return ll->ll_state;108}109110/* called from ST Core, when a PM related packet arrives */111unsigned long st_ll_sleep_state(struct st_data_s *st_data,112unsigned char cmd)113{114switch (cmd) {115case LL_SLEEP_IND: /* sleep ind */116pr_debug("sleep indication recvd");117ll_device_want_to_sleep(st_data);118break;119case LL_SLEEP_ACK: /* sleep ack */120pr_err("sleep ack rcvd: host shouldn't");121break;122case LL_WAKE_UP_IND: /* wake ind */123pr_debug("wake indication recvd");124ll_device_want_to_wakeup(st_data);125break;126case LL_WAKE_UP_ACK: /* wake ack */127pr_debug("wake ack rcvd");128st_data->ll_state = ST_LL_AWAKE;129break;130default:131pr_err(" unknown input/state ");132return -EINVAL;133}134return 0;135}136137/* Called from ST CORE to initialize ST LL */138long st_ll_init(struct st_data_s *ll)139{140/* set state to invalid */141ll->ll_state = ST_LL_INVALID;142return 0;143}144145/* Called from ST CORE to de-initialize ST LL */146long st_ll_deinit(struct st_data_s *ll)147{148return 0;149}150151152