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