Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / misc / ti-st / st_ll.c
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 */
17 static 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
26 static 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
48 static 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 */
86 void 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 */
93 void 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 */
99 void 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 */
111 unsigned 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 */
118 unsigned 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 */
145 long 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 */
153 long st_ll_deinit(struct st_data_s *ll)
154 {
155         return 0;
156 }