1*45051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a0cc2f3bSPavan Savoy /* 3a0cc2f3bSPavan Savoy * Shared Transport driver 4a0cc2f3bSPavan Savoy * HCI-LL module responsible for TI proprietary HCI_LL protocol 5a0cc2f3bSPavan Savoy * Copyright (C) 2009-2010 Texas Instruments 6a0cc2f3bSPavan Savoy * Author: Pavan Savoy <pavan_savoy@ti.com> 7a0cc2f3bSPavan Savoy */ 8a0cc2f3bSPavan Savoy 9a0cc2f3bSPavan Savoy #define pr_fmt(fmt) "(stll) :" fmt 10a0cc2f3bSPavan Savoy #include <linux/skbuff.h> 11a0cc2f3bSPavan Savoy #include <linux/module.h> 120d7c5f25SPavan Savoy #include <linux/platform_device.h> 13a0cc2f3bSPavan Savoy #include <linux/ti_wilink_st.h> 14a0cc2f3bSPavan Savoy 15a0cc2f3bSPavan Savoy /**********************************************************************/ 16a0cc2f3bSPavan Savoy /* internal functions */ 17a0cc2f3bSPavan Savoy static void send_ll_cmd(struct st_data_s *st_data, 18a0cc2f3bSPavan Savoy unsigned char cmd) 19a0cc2f3bSPavan Savoy { 20a0cc2f3bSPavan Savoy 216710fcffSPavan Savoy pr_debug("%s: writing %x", __func__, cmd); 22a0cc2f3bSPavan Savoy st_int_write(st_data, &cmd, 1); 23a0cc2f3bSPavan Savoy return; 24a0cc2f3bSPavan Savoy } 25a0cc2f3bSPavan Savoy 26a0cc2f3bSPavan Savoy static void ll_device_want_to_sleep(struct st_data_s *st_data) 27a0cc2f3bSPavan Savoy { 280d7c5f25SPavan Savoy struct kim_data_s *kim_data; 290d7c5f25SPavan Savoy struct ti_st_plat_data *pdata; 300d7c5f25SPavan Savoy 31a0cc2f3bSPavan Savoy pr_debug("%s", __func__); 32a0cc2f3bSPavan Savoy /* sanity check */ 33a0cc2f3bSPavan Savoy if (st_data->ll_state != ST_LL_AWAKE) 34a0cc2f3bSPavan Savoy pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND" 35a0cc2f3bSPavan Savoy "in state %ld", st_data->ll_state); 36a0cc2f3bSPavan Savoy 37a0cc2f3bSPavan Savoy send_ll_cmd(st_data, LL_SLEEP_ACK); 38a0cc2f3bSPavan Savoy /* update state */ 39a0cc2f3bSPavan Savoy st_data->ll_state = ST_LL_ASLEEP; 400d7c5f25SPavan Savoy 410d7c5f25SPavan Savoy /* communicate to platform about chip asleep */ 420d7c5f25SPavan Savoy kim_data = st_data->kim_data; 430d7c5f25SPavan Savoy pdata = kim_data->kim_pdev->dev.platform_data; 440d7c5f25SPavan Savoy if (pdata->chip_asleep) 450d7c5f25SPavan Savoy pdata->chip_asleep(NULL); 46a0cc2f3bSPavan Savoy } 47a0cc2f3bSPavan Savoy 48a0cc2f3bSPavan Savoy static void ll_device_want_to_wakeup(struct st_data_s *st_data) 49a0cc2f3bSPavan Savoy { 500d7c5f25SPavan Savoy struct kim_data_s *kim_data; 510d7c5f25SPavan Savoy struct ti_st_plat_data *pdata; 520d7c5f25SPavan 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; 730d7c5f25SPavan Savoy 740d7c5f25SPavan Savoy /* communicate to platform about chip wakeup */ 750d7c5f25SPavan Savoy kim_data = st_data->kim_data; 760d7c5f25SPavan Savoy pdata = kim_data->kim_pdev->dev.platform_data; 77f3d9d365SMatthias Kaehlcke if (pdata->chip_awake) 780d7c5f25SPavan Savoy pdata->chip_awake(NULL); 79a0cc2f3bSPavan Savoy } 80a0cc2f3bSPavan Savoy 81a0cc2f3bSPavan Savoy /**********************************************************************/ 82a0cc2f3bSPavan Savoy /* functions invoked by ST Core */ 83a0cc2f3bSPavan Savoy 84a0cc2f3bSPavan Savoy /* called when ST Core wants to 85a0cc2f3bSPavan Savoy * enable ST LL */ 86a0cc2f3bSPavan Savoy void st_ll_enable(struct st_data_s *ll) 87a0cc2f3bSPavan Savoy { 88a0cc2f3bSPavan Savoy ll->ll_state = ST_LL_AWAKE; 89a0cc2f3bSPavan Savoy } 90a0cc2f3bSPavan Savoy 91a0cc2f3bSPavan Savoy /* called when ST Core /local module wants to 92a0cc2f3bSPavan Savoy * disable ST LL */ 93a0cc2f3bSPavan Savoy void st_ll_disable(struct st_data_s *ll) 94a0cc2f3bSPavan Savoy { 95a0cc2f3bSPavan Savoy ll->ll_state = ST_LL_INVALID; 96a0cc2f3bSPavan Savoy } 97a0cc2f3bSPavan Savoy 98a0cc2f3bSPavan Savoy /* called when ST Core wants to update the state */ 99a0cc2f3bSPavan Savoy void st_ll_wakeup(struct st_data_s *ll) 100a0cc2f3bSPavan Savoy { 101a0cc2f3bSPavan Savoy if (likely(ll->ll_state != ST_LL_AWAKE)) { 102a0cc2f3bSPavan Savoy send_ll_cmd(ll, LL_WAKE_UP_IND); /* WAKE_IND */ 103a0cc2f3bSPavan Savoy ll->ll_state = ST_LL_ASLEEP_TO_AWAKE; 104a0cc2f3bSPavan Savoy } else { 105a0cc2f3bSPavan Savoy /* don't send the duplicate wake_indication */ 106a0cc2f3bSPavan Savoy pr_err(" Chip already AWAKE "); 107a0cc2f3bSPavan Savoy } 108a0cc2f3bSPavan Savoy } 109a0cc2f3bSPavan Savoy 110a0cc2f3bSPavan Savoy /* called when ST Core wants the state */ 111a0cc2f3bSPavan Savoy unsigned long st_ll_getstate(struct st_data_s *ll) 112a0cc2f3bSPavan Savoy { 113a0cc2f3bSPavan Savoy pr_debug(" returning state %ld", ll->ll_state); 114a0cc2f3bSPavan Savoy return ll->ll_state; 115a0cc2f3bSPavan Savoy } 116a0cc2f3bSPavan Savoy 117a0cc2f3bSPavan Savoy /* called from ST Core, when a PM related packet arrives */ 118a0cc2f3bSPavan Savoy unsigned long st_ll_sleep_state(struct st_data_s *st_data, 119a0cc2f3bSPavan Savoy unsigned char cmd) 120a0cc2f3bSPavan Savoy { 121a0cc2f3bSPavan Savoy switch (cmd) { 122a0cc2f3bSPavan Savoy case LL_SLEEP_IND: /* sleep ind */ 1236710fcffSPavan Savoy pr_debug("sleep indication recvd"); 124a0cc2f3bSPavan Savoy ll_device_want_to_sleep(st_data); 125a0cc2f3bSPavan Savoy break; 126a0cc2f3bSPavan Savoy case LL_SLEEP_ACK: /* sleep ack */ 127a0cc2f3bSPavan Savoy pr_err("sleep ack rcvd: host shouldn't"); 128a0cc2f3bSPavan Savoy break; 129a0cc2f3bSPavan Savoy case LL_WAKE_UP_IND: /* wake ind */ 1306710fcffSPavan Savoy pr_debug("wake indication recvd"); 131a0cc2f3bSPavan Savoy ll_device_want_to_wakeup(st_data); 132a0cc2f3bSPavan Savoy break; 133a0cc2f3bSPavan Savoy case LL_WAKE_UP_ACK: /* wake ack */ 1346710fcffSPavan Savoy pr_debug("wake ack rcvd"); 135a0cc2f3bSPavan Savoy st_data->ll_state = ST_LL_AWAKE; 136a0cc2f3bSPavan Savoy break; 137a0cc2f3bSPavan Savoy default: 138a0cc2f3bSPavan Savoy pr_err(" unknown input/state "); 13970442664SPavan Savoy return -EINVAL; 140a0cc2f3bSPavan Savoy } 141a0cc2f3bSPavan Savoy return 0; 142a0cc2f3bSPavan Savoy } 143a0cc2f3bSPavan Savoy 144a0cc2f3bSPavan Savoy /* Called from ST CORE to initialize ST LL */ 145a0cc2f3bSPavan Savoy long st_ll_init(struct st_data_s *ll) 146a0cc2f3bSPavan Savoy { 147a0cc2f3bSPavan Savoy /* set state to invalid */ 148a0cc2f3bSPavan Savoy ll->ll_state = ST_LL_INVALID; 149a0cc2f3bSPavan Savoy return 0; 150a0cc2f3bSPavan Savoy } 151a0cc2f3bSPavan Savoy 152a0cc2f3bSPavan Savoy /* Called from ST CORE to de-initialize ST LL */ 153a0cc2f3bSPavan Savoy long st_ll_deinit(struct st_data_s *ll) 154a0cc2f3bSPavan Savoy { 155a0cc2f3bSPavan Savoy return 0; 156a0cc2f3bSPavan Savoy } 157