aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNishanth Menon2015-11-06 18:11:23 -0600
committerTero Kristo2015-11-09 03:39:29 -0600
commitb90fea33c1560b69b5cb50a1da992ede077a37b4 (patch)
treee0f7b2e0efc4158a3b099e331da7182be8e28214 /drivers/firmware/ti_sci.c
parent1edda4194e17a1011aaa54199f31d07ae3df3e9a (diff)
downloadti-linux-kernel-b90fea33c1560b69b5cb50a1da992ede077a37b4.tar.gz
ti-linux-kernel-b90fea33c1560b69b5cb50a1da992ede077a37b4.tar.xz
ti-linux-kernel-b90fea33c1560b69b5cb50a1da992ede077a37b4.zip
firmware: ti_sci: Add support for Clock control
Texas Instrument's System Control Interface (TI-SCI) Message Protocol is used in Texas Instrument's System on Chip (SoC) such as those in keystone family K2G SoC to communicate between various compute processors with a central system controller entity. SCI message protocol provides support for management of various hardware entitites within the SoC. Add support driver to allow communication with system controller entity within the SoC using the mailbox client. In general, we expect to function at a device level of abstraction, however, for proper operation of hardware blocks, many clocks directly supplying the hardware block needs to be queried or configured. Introduce support for the set of SCI message protocol support that provide us with this capability. Signed-off-by: Nishanth Menon <nm@ti.com>
Diffstat (limited to 'drivers/firmware/ti_sci.c')
-rw-r--r--drivers/firmware/ti_sci.c685
1 files changed, 685 insertions, 0 deletions
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 1e9a2a68c471..51194b3cbbaf 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -837,6 +837,675 @@ static int ti_sci_cmd_dev_is_trans(const struct ti_sci_handle *handle, u32 id,
837} 837}
838 838
839/** 839/**
840 * ti_sci_set_clock_state() - Set clock state helper
841 * @handle: pointer to TI SCI handle
842 * @dev_id: Device identifier this request is for
843 * @clk_id: Clock identifier for the device for this request.
844 * Each device has it's own set of clock inputs. This indexes
845 * which clock input to modify.
846 * @flags: Header flags as needed
847 * @state: State to request for the clock.
848 *
849 * Return: 0 if all went well, else returns appropriate error value.
850 */
851static int ti_sci_set_clock_state(const struct ti_sci_handle *handle,
852 u32 dev_id, u8 clk_id,
853 u32 flags, u8 state)
854{
855 struct ti_sci_info *info;
856 struct ti_sci_msg_req_set_clock_state *req;
857 struct ti_sci_msg_hdr *resp;
858 struct ti_sci_xfer *xfer;
859 struct device *dev;
860 int ret = 0;
861
862 if (IS_ERR(handle))
863 return PTR_ERR(handle);
864 if (!handle)
865 return -EINVAL;
866
867 info = handle_to_ti_sci_info(handle);
868 dev = info->dev;
869
870 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CLOCK_STATE,
871 flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
872 sizeof(*req), sizeof(*resp));
873 if (IS_ERR(xfer)) {
874 ret = PTR_ERR(xfer);
875 dev_err(dev, "Message alloc failed(%d)\n", ret);
876 return ret;
877 }
878 req = (struct ti_sci_msg_req_set_clock_state *)xfer->xfer_buf;
879 req->dev_id = dev_id;
880 req->clk_id = clk_id;
881 req->request_state = state;
882
883 ret = ti_sci_do_xfer(info, xfer);
884 if (ret) {
885 dev_err(dev, "Mbox send fail %d\n", ret);
886 goto fail;
887 }
888
889 resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
890
891 ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV;
892
893fail:
894 ti_sci_put_one_xfer(&info->minfo, xfer);
895
896 return ret;
897}
898
899/**
900 * ti_sci_cmd_get_clock_state() - Get clock state helper
901 * @handle: pointer to TI SCI handle
902 * @dev_id: Device identifier this request is for
903 * @clk_id: Clock identifier for the device for this request.
904 * Each device has it's own set of clock inputs. This indexes
905 * which clock input to modify.
906 * @programmed_state: State requested for clock to move to
907 * @current_state: State that the clock is currently in
908 *
909 * Return: 0 if all went well, else returns appropriate error value.
910 */
911static int ti_sci_cmd_get_clock_state(const struct ti_sci_handle *handle,
912 u32 dev_id, u8 clk_id,
913 u8 *programmed_state, u8 *current_state)
914{
915 struct ti_sci_info *info;
916 struct ti_sci_msg_req_get_clock_state *req;
917 struct ti_sci_msg_resp_get_clock_state *resp;
918 struct ti_sci_xfer *xfer;
919 struct device *dev;
920 int ret = 0;
921
922 if (IS_ERR(handle))
923 return PTR_ERR(handle);
924 if (!handle)
925 return -EINVAL;
926
927 if (!programmed_state && !current_state)
928 return -EINVAL;
929
930 info = handle_to_ti_sci_info(handle);
931 dev = info->dev;
932
933 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_CLOCK_STATE,
934 TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
935 sizeof(*req), sizeof(*resp));
936 if (IS_ERR(xfer)) {
937 ret = PTR_ERR(xfer);
938 dev_err(dev, "Message alloc failed(%d)\n", ret);
939 return ret;
940 }
941 req = (struct ti_sci_msg_req_get_clock_state *)xfer->xfer_buf;
942 req->dev_id = dev_id;
943 req->clk_id = clk_id;
944
945 ret = ti_sci_do_xfer(info, xfer);
946 if (ret) {
947 dev_err(dev, "Mbox send fail %d\n", ret);
948 goto fail;
949 }
950
951 resp = (struct ti_sci_msg_resp_get_clock_state *)xfer->xfer_buf;
952
953 if (!tis_sci_is_response_ack(resp)) {
954 ret = -ENODEV;
955 goto fail;
956 }
957
958 if (programmed_state)
959 *programmed_state = resp->programmed_state;
960 if (current_state)
961 *current_state = resp->current_state;
962
963fail:
964 ti_sci_put_one_xfer(&info->minfo, xfer);
965
966 return ret;
967}
968
969/**
970 * ti_sci_cmd_get_clock() - Get control of a clock from TI SCI
971 * @handle: pointer to TI SCI handle
972 * @dev_id: Device identifier this request is for
973 * @clk_id: Clock identifier for the device for this request.
974 * Each device has it's own set of clock inputs. This indexes
975 * which clock input to modify.
976 * @needs_ssc: 'true' if Spread Spectrum clock is desired, else 'false'
977 * @can_change_freq: 'true' if frequency change is desired, else 'false'
978 * @enable_input_term: 'true' if input termination is desired, else 'false'
979 *
980 * Return: 0 if all went well, else returns appropriate error value.
981 */
982static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
983 u8 clk_id, bool needs_ssc, bool can_change_freq,
984 bool enable_input_term)
985{
986 u32 flags = 0;
987
988 flags |= needs_ssc ? MSG_FLAG_CLOCK_ALLOW_SSC : 0;
989 flags |= can_change_freq ? MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE : 0;
990 flags |= enable_input_term ? MSG_FLAG_CLOCK_INPUT_TERM : 0;
991
992 return ti_sci_set_clock_state(handle, dev_id, clk_id, flags,
993 MSG_CLOCK_SW_STATE_REQ);
994}
995
996/**
997 * ti_sci_cmd_idle_clock() - Idle a clock which is in our control
998 * @handle: pointer to TI SCI handle
999 * @dev_id: Device identifier this request is for
1000 * @clk_id: Clock identifier for the device for this request.
1001 * Each device has it's own set of clock inputs. This indexes
1002 * which clock input to modify.
1003 *
1004 * NOTE: This clock must have been requested by get_clock previously.
1005 *
1006 * Return: 0 if all went well, else returns appropriate error value.
1007 */
1008static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
1009 u32 dev_id, u8 clk_id)
1010{
1011 return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
1012 MSG_CLOCK_SW_STATE_UNREQ);
1013}
1014
1015/**
1016 * ti_sci_cmd_put_clock() - Release a clock from our control back to TISCI
1017 * @handle: pointer to TI SCI handle
1018 * @dev_id: Device identifier this request is for
1019 * @clk_id: Clock identifier for the device for this request.
1020 * Each device has it's own set of clock inputs. This indexes
1021 * which clock input to modify.
1022 *
1023 * NOTE: This clock must have been requested by get_clock previously.
1024 *
1025 * Return: 0 if all went well, else returns appropriate error value.
1026 */
1027static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
1028 u32 dev_id, u8 clk_id)
1029{
1030 return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
1031 MSG_CLOCK_SW_STATE_AUTO);
1032}
1033
1034/**
1035 * ti_sci_cmd_clk_is_auto() - Is the clock being auto managed
1036 * @handle: pointer to TI SCI handle
1037 * @dev_id: Device identifier this request is for
1038 * @clk_id: Clock identifier for the device for this request.
1039 * Each device has it's own set of clock inputs. This indexes
1040 * which clock input to modify.
1041 * @req_state: state indicating if the clock is auto managed
1042 *
1043 * Return: 0 if all went well, else returns appropriate error value.
1044 */
1045static int ti_sci_cmd_clk_is_auto(const struct ti_sci_handle *handle,
1046 u32 dev_id, u8 clk_id, bool *req_state)
1047{
1048 u8 state = 0;
1049 int ret;
1050
1051 if (!req_state)
1052 return -EINVAL;
1053
1054 ret = ti_sci_cmd_get_clock_state(handle, dev_id, clk_id, &state, NULL);
1055 if (ret)
1056 return ret;
1057
1058 *req_state = (state == MSG_CLOCK_SW_STATE_AUTO);
1059 return 0;
1060}
1061
1062/**
1063 * ti_sci_cmd_clk_is_on() - Is the clock ON
1064 * @handle: pointer to TI SCI handle
1065 * @dev_id: Device identifier this request is for
1066 * @clk_id: Clock identifier for the device for this request.
1067 * Each device has it's own set of clock inputs. This indexes
1068 * which clock input to modify.
1069 * @req_state: state indicating if the clock is managed by us and enabled
1070 * @curr_state: state indicating if the clock is ready for operation
1071 *
1072 * Return: 0 if all went well, else returns appropriate error value.
1073 */
1074static int ti_sci_cmd_clk_is_on(const struct ti_sci_handle *handle, u32 dev_id,
1075 u8 clk_id, bool *req_state, bool *curr_state)
1076{
1077 u8 c_state = 0, r_state = 0;
1078 int ret;
1079
1080 if (!req_state && !curr_state)
1081 return -EINVAL;
1082
1083 ret = ti_sci_cmd_get_clock_state(handle, dev_id, clk_id,
1084 &r_state, &c_state);
1085 if (ret)
1086 return ret;
1087
1088 if (req_state)
1089 *req_state = (r_state == MSG_CLOCK_SW_STATE_REQ);
1090 if (curr_state)
1091 *curr_state = (c_state == MSG_CLOCK_HW_STATE_READY);
1092 return 0;
1093}
1094
1095/**
1096 * ti_sci_cmd_clk_is_off() - Is the clock OFF
1097 * @handle: pointer to TI SCI handle
1098 * @dev_id: Device identifier this request is for
1099 * @clk_id: Clock identifier for the device for this request.
1100 * Each device has it's own set of clock inputs. This indexes
1101 * which clock input to modify.
1102 * @req_state: state indicating if the clock is managed by us and disabled
1103 * @curr_state: state indicating if the clock is NOT ready for operation
1104 *
1105 * Return: 0 if all went well, else returns appropriate error value.
1106 */
1107static int ti_sci_cmd_clk_is_off(const struct ti_sci_handle *handle, u32 dev_id,
1108 u8 clk_id, bool *req_state, bool *curr_state)
1109{
1110 u8 c_state = 0, r_state = 0;
1111 int ret;
1112
1113 if (!req_state && !curr_state)
1114 return -EINVAL;
1115
1116 ret = ti_sci_cmd_get_clock_state(handle, dev_id, clk_id,
1117 &r_state, &c_state);
1118 if (ret)
1119 return ret;
1120
1121 if (req_state)
1122 *req_state = (r_state == MSG_CLOCK_SW_STATE_UNREQ);
1123 if (curr_state)
1124 *curr_state = (c_state == MSG_CLOCK_HW_STATE_NOT_READY);
1125 return 0;
1126}
1127
1128/**
1129 * ti_sci_cmd_clk_set_parent() - Set the clock source of a specific device clock
1130 * @handle: pointer to TI SCI handle
1131 * @dev_id: Device identifier this request is for
1132 * @clk_id: Clock identifier for the device for this request.
1133 * Each device has it's own set of clock inputs. This indexes
1134 * which clock input to modify.
1135 * @parent_id: Parent clock identifier to set
1136 *
1137 * Return: 0 if all went well, else returns appropriate error value.
1138 */
1139static int ti_sci_cmd_clk_set_parent(const struct ti_sci_handle *handle,
1140 u32 dev_id, u8 clk_id, u8 parent_id)
1141{
1142 struct ti_sci_info *info;
1143 struct ti_sci_msg_req_set_clock_parent *req;
1144 struct ti_sci_msg_hdr *resp;
1145 struct ti_sci_xfer *xfer;
1146 struct device *dev;
1147 int ret = 0;
1148
1149 if (IS_ERR(handle))
1150 return PTR_ERR(handle);
1151 if (!handle)
1152 return -EINVAL;
1153
1154 info = handle_to_ti_sci_info(handle);
1155 dev = info->dev;
1156
1157 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CLOCK_PARENT,
1158 TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
1159 sizeof(*req), sizeof(*resp));
1160 if (IS_ERR(xfer)) {
1161 ret = PTR_ERR(xfer);
1162 dev_err(dev, "Message alloc failed(%d)\n", ret);
1163 return ret;
1164 }
1165 req = (struct ti_sci_msg_req_set_clock_parent *)xfer->xfer_buf;
1166 req->dev_id = dev_id;
1167 req->clk_id = clk_id;
1168 req->parent_id = parent_id;
1169
1170 ret = ti_sci_do_xfer(info, xfer);
1171 if (ret) {
1172 dev_err(dev, "Mbox send fail %d\n", ret);
1173 goto fail;
1174 }
1175
1176 resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
1177
1178 ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV;
1179
1180fail:
1181 ti_sci_put_one_xfer(&info->minfo, xfer);
1182
1183 return ret;
1184}
1185
1186/**
1187 * ti_sci_cmd_clk_get_parent() - Get current parent clock source
1188 * @handle: pointer to TI SCI handle
1189 * @dev_id: Device identifier this request is for
1190 * @clk_id: Clock identifier for the device for this request.
1191 * Each device has it's own set of clock inputs. This indexes
1192 * which clock input to modify.
1193 * @parent_id: Current clock parent
1194 *
1195 * Return: 0 if all went well, else returns appropriate error value.
1196 */
1197static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
1198 u32 dev_id, u8 clk_id, u8 *parent_id)
1199{
1200 struct ti_sci_info *info;
1201 struct ti_sci_msg_req_get_clock_parent *req;
1202 struct ti_sci_msg_resp_get_clock_parent *resp;
1203 struct ti_sci_xfer *xfer;
1204 struct device *dev;
1205 int ret = 0;
1206
1207 if (IS_ERR(handle))
1208 return PTR_ERR(handle);
1209 if (!handle || !parent_id)
1210 return -EINVAL;
1211
1212 info = handle_to_ti_sci_info(handle);
1213 dev = info->dev;
1214
1215 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_CLOCK_PARENT,
1216 TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
1217 sizeof(*req), sizeof(*resp));
1218 if (IS_ERR(xfer)) {
1219 ret = PTR_ERR(xfer);
1220 dev_err(dev, "Message alloc failed(%d)\n", ret);
1221 return ret;
1222 }
1223 req = (struct ti_sci_msg_req_get_clock_parent *)xfer->xfer_buf;
1224 req->dev_id = dev_id;
1225 req->clk_id = clk_id;
1226
1227 ret = ti_sci_do_xfer(info, xfer);
1228 if (ret) {
1229 dev_err(dev, "Mbox send fail %d\n", ret);
1230 goto fail;
1231 }
1232
1233 resp = (struct ti_sci_msg_resp_get_clock_parent *)xfer->xfer_buf;
1234
1235 if (!tis_sci_is_response_ack(resp))
1236 ret = -ENODEV;
1237 else
1238 *parent_id = resp->parent_id;
1239
1240fail:
1241 ti_sci_put_one_xfer(&info->minfo, xfer);
1242
1243 return ret;
1244}
1245
1246/**
1247 * ti_sci_cmd_clk_get_num_parents() - Get the number of parents of the current clock source
1248 * @handle: pointer to TI SCI handle
1249 * @dev_id: Device identifier this request is for
1250 * @clk_id: Clock identifier for the device for this request.
1251 * Each device has it's own set of clock inputs. This indexes
1252 * which clock input to modify.
1253 * @num_parents: Returns he number of parents to the current clock.
1254 *
1255 * Return: 0 if all went well, else returns appropriate error value.
1256 */
1257static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle,
1258 u32 dev_id, u8 clk_id,
1259 u8 *num_parents)
1260{
1261 struct ti_sci_info *info;
1262 struct ti_sci_msg_req_get_clock_num_parents *req;
1263 struct ti_sci_msg_resp_get_clock_num_parents *resp;
1264 struct ti_sci_xfer *xfer;
1265 struct device *dev;
1266 int ret = 0;
1267
1268 if (IS_ERR(handle))
1269 return PTR_ERR(handle);
1270 if (!handle || !num_parents)
1271 return -EINVAL;
1272
1273 info = handle_to_ti_sci_info(handle);
1274 dev = info->dev;
1275
1276 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_NUM_CLOCK_PARENTS,
1277 TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
1278 sizeof(*req), sizeof(*resp));
1279 if (IS_ERR(xfer)) {
1280 ret = PTR_ERR(xfer);
1281 dev_err(dev, "Message alloc failed(%d)\n", ret);
1282 return ret;
1283 }
1284 req = (struct ti_sci_msg_req_get_clock_num_parents *)xfer->xfer_buf;
1285 req->dev_id = dev_id;
1286 req->clk_id = clk_id;
1287
1288 ret = ti_sci_do_xfer(info, xfer);
1289 if (ret) {
1290 dev_err(dev, "Mbox send fail %d\n", ret);
1291 goto fail;
1292 }
1293
1294 resp = (struct ti_sci_msg_resp_get_clock_num_parents *)xfer->xfer_buf;
1295
1296 if (!tis_sci_is_response_ack(resp))
1297 ret = -ENODEV;
1298 else
1299 *num_parents = resp->num_parents;
1300
1301fail:
1302 ti_sci_put_one_xfer(&info->minfo, xfer);
1303
1304 return ret;
1305}
1306
1307/**
1308 * ti_sci_cmd_clk_get_match_freq() - Find a good match for frequency
1309 * @handle: pointer to TI SCI handle
1310 * @dev_id: Device identifier this request is for
1311 * @clk_id: Clock identifier for the device for this request.
1312 * Each device has it's own set of clock inputs. This indexes
1313 * which clock input to modify.
1314 * @min_freq: The minimum allowable frequency in Hz. This is the minimum
1315 * allowable programmed frequency and does not account for clock
1316 * tolerances and jitter.
1317 * @target_freq: The target clock frequency in Hz. A frequency will be
1318 * processed as close to this target frequency as possible.
1319 * @max_freq: The maximum allowable frequency in Hz. This is the maximum
1320 * allowable programmed frequency and does not account for clock
1321 * tolerances and jitter.
1322 * @match_freq: Frequency match in Hz response.
1323 *
1324 * Return: 0 if all went well, else returns appropriate error value.
1325 */
1326static int ti_sci_cmd_clk_get_match_freq(const struct ti_sci_handle *handle,
1327 u32 dev_id, u8 clk_id, u64 min_freq,
1328 u64 target_freq, u64 max_freq,
1329 u64 *match_freq)
1330{
1331 struct ti_sci_info *info;
1332 struct ti_sci_msg_req_query_clock_freq *req;
1333 struct ti_sci_msg_resp_query_clock_freq *resp;
1334 struct ti_sci_xfer *xfer;
1335 struct device *dev;
1336 int ret = 0;
1337
1338 if (IS_ERR(handle))
1339 return PTR_ERR(handle);
1340 if (!handle || !match_freq)
1341 return -EINVAL;
1342
1343 info = handle_to_ti_sci_info(handle);
1344 dev = info->dev;
1345
1346 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_QUERY_CLOCK_FREQ,
1347 TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
1348 sizeof(*req), sizeof(*resp));
1349 if (IS_ERR(xfer)) {
1350 ret = PTR_ERR(xfer);
1351 dev_err(dev, "Message alloc failed(%d)\n", ret);
1352 return ret;
1353 }
1354 req = (struct ti_sci_msg_req_query_clock_freq *)xfer->xfer_buf;
1355 req->dev_id = dev_id;
1356 req->clk_id = clk_id;
1357 req->min_freq_hz = min_freq;
1358 req->target_freq_hz = target_freq;
1359 req->max_freq_hz = max_freq;
1360
1361 ret = ti_sci_do_xfer(info, xfer);
1362 if (ret) {
1363 dev_err(dev, "Mbox send fail %d\n", ret);
1364 goto fail;
1365 }
1366
1367 resp = (struct ti_sci_msg_resp_query_clock_freq *)xfer->xfer_buf;
1368
1369 if (!tis_sci_is_response_ack(resp))
1370 ret = -ENODEV;
1371 else
1372 *match_freq = resp->freq_hz;
1373
1374fail:
1375 ti_sci_put_one_xfer(&info->minfo, xfer);
1376
1377 return ret;
1378}
1379
1380/**
1381 * ti_sci_cmd_clk_set_freq() - Set a frequency for clock
1382 * @handle: pointer to TI SCI handle
1383 * @dev_id: Device identifier this request is for
1384 * @clk_id: Clock identifier for the device for this request.
1385 * Each device has it's own set of clock inputs. This indexes
1386 * which clock input to modify.
1387 * @min_freq: The minimum allowable frequency in Hz. This is the minimum
1388 * allowable programmed frequency and does not account for clock
1389 * tolerances and jitter.
1390 * @target_freq: The target clock frequency in Hz. A frequency will be
1391 * processed as close to this target frequency as possible.
1392 * @max_freq: The maximum allowable frequency in Hz. This is the maximum
1393 * allowable programmed frequency and does not account for clock
1394 * tolerances and jitter.
1395 *
1396 * Return: 0 if all went well, else returns appropriate error value.
1397 */
1398static int ti_sci_cmd_clk_set_freq(const struct ti_sci_handle *handle,
1399 u32 dev_id, u8 clk_id, u64 min_freq,
1400 u64 target_freq, u64 max_freq)
1401{
1402 struct ti_sci_info *info;
1403 struct ti_sci_msg_req_set_clock_freq *req;
1404 struct ti_sci_msg_hdr *resp;
1405 struct ti_sci_xfer *xfer;
1406 struct device *dev;
1407 int ret = 0;
1408
1409 if (IS_ERR(handle))
1410 return PTR_ERR(handle);
1411 if (!handle)
1412 return -EINVAL;
1413
1414 info = handle_to_ti_sci_info(handle);
1415 dev = info->dev;
1416
1417 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CLOCK_FREQ,
1418 TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
1419 sizeof(*req), sizeof(*resp));
1420 if (IS_ERR(xfer)) {
1421 ret = PTR_ERR(xfer);
1422 dev_err(dev, "Message alloc failed(%d)\n", ret);
1423 return ret;
1424 }
1425 req = (struct ti_sci_msg_req_set_clock_freq *)xfer->xfer_buf;
1426 req->dev_id = dev_id;
1427 req->clk_id = clk_id;
1428 req->min_freq_hz = min_freq;
1429 req->target_freq_hz = target_freq;
1430 req->max_freq_hz = max_freq;
1431
1432 ret = ti_sci_do_xfer(info, xfer);
1433 if (ret) {
1434 dev_err(dev, "Mbox send fail %d\n", ret);
1435 goto fail;
1436 }
1437
1438 resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf;
1439
1440 ret = tis_sci_is_response_ack(resp) ? 0 : -ENODEV;
1441
1442fail:
1443 ti_sci_put_one_xfer(&info->minfo, xfer);
1444
1445 return ret;
1446}
1447
1448/**
1449 * ti_sci_cmd_clk_get_freq() - Get current frequency
1450 * @handle: pointer to TI SCI handle
1451 * @dev_id: Device identifier this request is for
1452 * @clk_id: Clock identifier for the device for this request.
1453 * Each device has it's own set of clock inputs. This indexes
1454 * which clock input to modify.
1455 * @freq: Currently frequency in Hz
1456 *
1457 * Return: 0 if all went well, else returns appropriate error value.
1458 */
1459static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle,
1460 u32 dev_id, u8 clk_id, u64 *freq)
1461{
1462 struct ti_sci_info *info;
1463 struct ti_sci_msg_req_get_clock_freq *req;
1464 struct ti_sci_msg_resp_get_clock_freq *resp;
1465 struct ti_sci_xfer *xfer;
1466 struct device *dev;
1467 int ret = 0;
1468
1469 if (IS_ERR(handle))
1470 return PTR_ERR(handle);
1471 if (!handle || !freq)
1472 return -EINVAL;
1473
1474 info = handle_to_ti_sci_info(handle);
1475 dev = info->dev;
1476
1477 xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_CLOCK_FREQ,
1478 TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
1479 sizeof(*req), sizeof(*resp));
1480 if (IS_ERR(xfer)) {
1481 ret = PTR_ERR(xfer);
1482 dev_err(dev, "Message alloc failed(%d)\n", ret);
1483 return ret;
1484 }
1485 req = (struct ti_sci_msg_req_get_clock_freq *)xfer->xfer_buf;
1486 req->dev_id = dev_id;
1487 req->clk_id = clk_id;
1488
1489 ret = ti_sci_do_xfer(info, xfer);
1490 if (ret) {
1491 dev_err(dev, "Mbox send fail %d\n", ret);
1492 goto fail;
1493 }
1494
1495 resp = (struct ti_sci_msg_resp_get_clock_freq *)xfer->xfer_buf;
1496
1497 if (!tis_sci_is_response_ack(resp))
1498 ret = -ENODEV;
1499 else
1500 *freq = resp->freq_hz;
1501
1502fail:
1503 ti_sci_put_one_xfer(&info->minfo, xfer);
1504
1505 return ret;
1506}
1507
1508/**
840 * ti_sci_setup_ops() - Setup the operations structures 1509 * ti_sci_setup_ops() - Setup the operations structures
841 * @info: pointer to TISCI pointer 1510 * @info: pointer to TISCI pointer
842 */ 1511 */
@@ -844,6 +1513,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
844{ 1513{
845 struct ti_sci_ops *ops = &info->handle.ops; 1514 struct ti_sci_ops *ops = &info->handle.ops;
846 struct ti_sci_dev_ops *dops = &ops->dev_ops; 1515 struct ti_sci_dev_ops *dops = &ops->dev_ops;
1516 struct ti_sci_clk_ops *cops = &ops->clk_ops;
847 1517
848 dops->get_device = ti_sci_cmd_get_device; 1518 dops->get_device = ti_sci_cmd_get_device;
849 dops->idle_device = ti_sci_cmd_idle_device; 1519 dops->idle_device = ti_sci_cmd_idle_device;
@@ -855,6 +1525,21 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
855 dops->is_stop = ti_sci_cmd_dev_is_stop; 1525 dops->is_stop = ti_sci_cmd_dev_is_stop;
856 dops->is_on = ti_sci_cmd_dev_is_on; 1526 dops->is_on = ti_sci_cmd_dev_is_on;
857 dops->is_transitioning = ti_sci_cmd_dev_is_trans; 1527 dops->is_transitioning = ti_sci_cmd_dev_is_trans;
1528
1529 cops->get_clock = ti_sci_cmd_get_clock;
1530 cops->idle_clock = ti_sci_cmd_idle_clock;
1531 cops->put_clock = ti_sci_cmd_put_clock;
1532 cops->is_auto = ti_sci_cmd_clk_is_auto;
1533 cops->is_on = ti_sci_cmd_clk_is_on;
1534 cops->is_off = ti_sci_cmd_clk_is_off;
1535
1536 cops->set_parent = ti_sci_cmd_clk_set_parent;
1537 cops->get_parent = ti_sci_cmd_clk_get_parent;
1538 cops->get_num_parents = ti_sci_cmd_clk_get_num_parents;
1539
1540 cops->get_best_match_freq = ti_sci_cmd_clk_get_match_freq;
1541 cops->set_freq = ti_sci_cmd_clk_set_freq;
1542 cops->get_freq = ti_sci_cmd_clk_get_freq;
858} 1543}
859 1544
860/** 1545/**