2 * Copyright (c) 2014 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <linux/slab.h>
19 #include <linux/msm-bus.h>
21 #include "wil_platform.h"
22 #include "wil_platform_msm.h"
25 * struct wil_platform_msm - wil6210 msm platform module info
28 * @msm_bus_handle: handle for using msm_bus API
29 * @pdata: bus scale info retrieved from DT
31 struct wil_platform_msm
{
33 uint32_t msm_bus_handle
;
34 struct msm_bus_scale_pdata
*pdata
;
37 #define KBTOB(a) (a * 1000ULL)
40 * wil_platform_get_pdata() - Generate bus client data from device tree
41 * provided by clients.
44 * of_node: Device tree node to extract information from
46 * The function returns a valid pointer to the allocated bus-scale-pdata
47 * if the vectors were correctly read from the client's device node.
48 * Any error in reading or parsing the device node will return NULL
51 static struct msm_bus_scale_pdata
*wil_platform_get_pdata(
53 struct device_node
*of_node
)
55 struct msm_bus_scale_pdata
*pdata
;
56 struct msm_bus_paths
*usecase
;
58 unsigned int num_usecases
, num_paths
, mem_size
;
59 const uint32_t *vec_arr
;
60 struct msm_bus_vectors
*vectors
;
62 /* first read num_usecases and num_paths so we can calculate
63 * amount of memory to allocate
65 ret
= of_property_read_u32(of_node
, "qcom,msm-bus,num-cases",
68 dev_err(dev
, "Error: num-usecases not found\n");
72 ret
= of_property_read_u32(of_node
, "qcom,msm-bus,num-paths",
75 dev_err(dev
, "Error: num_paths not found\n");
79 /* pdata memory layout:
81 * msm_bus_paths[num_usecases]
82 * msm_bus_vectors[num_usecases][num_paths]
84 mem_size
= sizeof(struct msm_bus_scale_pdata
) +
85 sizeof(struct msm_bus_paths
) * num_usecases
+
86 sizeof(struct msm_bus_vectors
) * num_usecases
* num_paths
;
88 pdata
= kzalloc(mem_size
, GFP_KERNEL
);
92 ret
= of_property_read_string(of_node
, "qcom,msm-bus,name",
95 dev_err(dev
, "Error: Client name not found\n");
99 if (of_property_read_bool(of_node
, "qcom,msm-bus,active-only")) {
100 pdata
->active_only
= 1;
102 dev_info(dev
, "active_only flag absent.\n");
103 dev_info(dev
, "Using dual context by default\n");
106 pdata
->num_usecases
= num_usecases
;
107 pdata
->usecase
= (struct msm_bus_paths
*)(pdata
+ 1);
109 vec_arr
= of_get_property(of_node
, "qcom,msm-bus,vectors-KBps", &len
);
110 if (vec_arr
== NULL
) {
111 dev_err(dev
, "Error: Vector array not found\n");
115 if (len
!= num_usecases
* num_paths
* sizeof(uint32_t) * 4) {
116 dev_err(dev
, "Error: Length-error on getting vectors\n");
120 vectors
= (struct msm_bus_vectors
*)(pdata
->usecase
+ num_usecases
);
121 for (i
= 0; i
< num_usecases
; i
++) {
122 usecase
= &pdata
->usecase
[i
];
123 usecase
->num_paths
= num_paths
;
124 usecase
->vectors
= &vectors
[i
];
126 for (j
= 0; j
< num_paths
; j
++) {
127 int index
= ((i
* num_paths
) + j
) * 4;
129 usecase
->vectors
[j
].src
= be32_to_cpu(vec_arr
[index
]);
130 usecase
->vectors
[j
].dst
=
131 be32_to_cpu(vec_arr
[index
+ 1]);
132 usecase
->vectors
[j
].ab
= (uint64_t)
133 KBTOB(be32_to_cpu(vec_arr
[index
+ 2]));
134 usecase
->vectors
[j
].ib
= (uint64_t)
135 KBTOB(be32_to_cpu(vec_arr
[index
+ 3]));
147 /* wil_platform API (callbacks) */
149 static int wil_platform_bus_request(void *handle
,
150 uint32_t kbps
/* KBytes/Sec */)
153 struct wil_platform_msm
*msm
= (struct wil_platform_msm
*)handle
;
154 int vote
= 0; /* vote 0 in case requested kbps cannot be satisfied */
155 struct msm_bus_paths
*usecase
;
156 uint32_t usecase_kbps
;
157 uint32_t min_kbps
= ~0;
159 /* find the lowest usecase that is bigger than requested kbps */
160 for (i
= 0; i
< msm
->pdata
->num_usecases
; i
++) {
161 usecase
= &msm
->pdata
->usecase
[i
];
162 /* assume we have single path (vectors[0]). If we ever
163 * have multiple paths, need to define the behavior */
164 usecase_kbps
= div64_u64(usecase
->vectors
[0].ib
, 1000);
165 if (usecase_kbps
>= kbps
&& usecase_kbps
< min_kbps
) {
166 min_kbps
= usecase_kbps
;
171 rc
= msm_bus_scale_client_update_request(msm
->msm_bus_handle
, vote
);
173 dev_err(msm
->dev
, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
177 dev_info(msm
->dev
, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n",
183 static void wil_platform_uninit(void *handle
)
185 struct wil_platform_msm
*msm
= (struct wil_platform_msm
*)handle
;
187 dev_info(msm
->dev
, "wil_platform_uninit\n");
189 if (msm
->msm_bus_handle
)
190 msm_bus_scale_unregister_client(msm
->msm_bus_handle
);
196 static int wil_platform_msm_bus_register(struct wil_platform_msm
*msm
,
197 struct device_node
*node
)
199 msm
->pdata
= wil_platform_get_pdata(msm
->dev
, node
);
201 dev_err(msm
->dev
, "Failed getting DT info\n");
205 msm
->msm_bus_handle
= msm_bus_scale_register_client(msm
->pdata
);
206 if (!msm
->msm_bus_handle
) {
207 dev_err(msm
->dev
, "Failed msm_bus registration\n");
211 dev_info(msm
->dev
, "msm_bus registration succeeded! handle 0x%x\n",
212 msm
->msm_bus_handle
);
218 * wil_platform_msm_init() - wil6210 msm platform module init
220 * The function must be called before all other functions in this module.
221 * It returns a handle which is used with the rest of the API
224 void *wil_platform_msm_init(struct device
*dev
, struct wil_platform_ops
*ops
)
226 struct device_node
*of_node
;
227 struct wil_platform_msm
*msm
;
230 of_node
= of_find_compatible_node(NULL
, NULL
, "qcom,wil6210");
232 /* this could mean non-msm platform */
233 dev_err(dev
, "DT node not found\n");
237 msm
= kzalloc(sizeof(*msm
), GFP_KERNEL
);
243 /* register with msm_bus module for scaling requests */
244 rc
= wil_platform_msm_bus_register(msm
, of_node
);
248 memset(ops
, 0, sizeof(*ops
));
249 ops
->bus_request
= wil_platform_bus_request
;
250 ops
->uninit
= wil_platform_uninit
;