linux/drivers/misc/ti-st/st_ll.c
<<
>>
Prefs
   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 */
  30static 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
  39static 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
  61static 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 */
  99void 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 */
 106void 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 */
 112void 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 */
 124unsigned 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 */
 131unsigned 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 */
 158long 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 */
 166long st_ll_deinit(struct st_data_s *ll)
 167{
 168        return 0;
 169}
 170