diff options
| -rw-r--r-- | drivers/clk/bcm/clk-bcm2835.c | 122 |
1 files changed, 77 insertions, 45 deletions
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 9e881eef3c36..6e4dd6fa3403 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c | |||
| @@ -1199,16 +1199,6 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock, | |||
| 1199 | return temp; | 1199 | return temp; |
| 1200 | } | 1200 | } |
| 1201 | 1201 | ||
| 1202 | static long bcm2835_clock_round_rate(struct clk_hw *hw, | ||
| 1203 | unsigned long rate, | ||
| 1204 | unsigned long *parent_rate) | ||
| 1205 | { | ||
| 1206 | struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); | ||
| 1207 | u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate, false); | ||
| 1208 | |||
| 1209 | return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div); | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, | 1202 | static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, |
| 1213 | unsigned long parent_rate) | 1203 | unsigned long parent_rate) |
| 1214 | { | 1204 | { |
| @@ -1280,13 +1270,75 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, | |||
| 1280 | return 0; | 1270 | return 0; |
| 1281 | } | 1271 | } |
| 1282 | 1272 | ||
| 1273 | static int bcm2835_clock_determine_rate(struct clk_hw *hw, | ||
| 1274 | struct clk_rate_request *req) | ||
| 1275 | { | ||
| 1276 | struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); | ||
| 1277 | struct clk_hw *parent, *best_parent = NULL; | ||
| 1278 | unsigned long rate, best_rate = 0; | ||
| 1279 | unsigned long prate, best_prate = 0; | ||
| 1280 | size_t i; | ||
| 1281 | u32 div; | ||
| 1282 | |||
| 1283 | /* | ||
| 1284 | * Select parent clock that results in the closest but lower rate | ||
| 1285 | */ | ||
| 1286 | for (i = 0; i < clk_hw_get_num_parents(hw); ++i) { | ||
| 1287 | parent = clk_hw_get_parent_by_index(hw, i); | ||
| 1288 | if (!parent) | ||
| 1289 | continue; | ||
| 1290 | prate = clk_hw_get_rate(parent); | ||
| 1291 | div = bcm2835_clock_choose_div(hw, req->rate, prate, true); | ||
| 1292 | rate = bcm2835_clock_rate_from_divisor(clock, prate, div); | ||
| 1293 | if (rate > best_rate && rate <= req->rate) { | ||
| 1294 | best_parent = parent; | ||
| 1295 | best_prate = prate; | ||
| 1296 | best_rate = rate; | ||
| 1297 | } | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | if (!best_parent) | ||
| 1301 | return -EINVAL; | ||
| 1302 | |||
| 1303 | req->best_parent_hw = best_parent; | ||
| 1304 | req->best_parent_rate = best_prate; | ||
| 1305 | |||
| 1306 | req->rate = best_rate; | ||
| 1307 | |||
| 1308 | return 0; | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | static int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index) | ||
| 1312 | { | ||
| 1313 | struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); | ||
| 1314 | struct bcm2835_cprman *cprman = clock->cprman; | ||
| 1315 | const struct bcm2835_clock_data *data = clock->data; | ||
| 1316 | u8 src = (index << CM_SRC_SHIFT) & CM_SRC_MASK; | ||
| 1317 | |||
| 1318 | cprman_write(cprman, data->ctl_reg, src); | ||
| 1319 | return 0; | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | static u8 bcm2835_clock_get_parent(struct clk_hw *hw) | ||
| 1323 | { | ||
| 1324 | struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); | ||
| 1325 | struct bcm2835_cprman *cprman = clock->cprman; | ||
| 1326 | const struct bcm2835_clock_data *data = clock->data; | ||
| 1327 | u32 src = cprman_read(cprman, data->ctl_reg); | ||
| 1328 | |||
| 1329 | return (src & CM_SRC_MASK) >> CM_SRC_SHIFT; | ||
| 1330 | } | ||
| 1331 | |||
| 1332 | |||
| 1283 | static const struct clk_ops bcm2835_clock_clk_ops = { | 1333 | static const struct clk_ops bcm2835_clock_clk_ops = { |
| 1284 | .is_prepared = bcm2835_clock_is_on, | 1334 | .is_prepared = bcm2835_clock_is_on, |
| 1285 | .prepare = bcm2835_clock_on, | 1335 | .prepare = bcm2835_clock_on, |
| 1286 | .unprepare = bcm2835_clock_off, | 1336 | .unprepare = bcm2835_clock_off, |
| 1287 | .recalc_rate = bcm2835_clock_get_rate, | 1337 | .recalc_rate = bcm2835_clock_get_rate, |
| 1288 | .set_rate = bcm2835_clock_set_rate, | 1338 | .set_rate = bcm2835_clock_set_rate, |
| 1289 | .round_rate = bcm2835_clock_round_rate, | 1339 | .determine_rate = bcm2835_clock_determine_rate, |
| 1340 | .set_parent = bcm2835_clock_set_parent, | ||
| 1341 | .get_parent = bcm2835_clock_get_parent, | ||
| 1290 | }; | 1342 | }; |
| 1291 | 1343 | ||
| 1292 | static int bcm2835_vpu_clock_is_on(struct clk_hw *hw) | 1344 | static int bcm2835_vpu_clock_is_on(struct clk_hw *hw) |
| @@ -1302,7 +1354,9 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { | |||
| 1302 | .is_prepared = bcm2835_vpu_clock_is_on, | 1354 | .is_prepared = bcm2835_vpu_clock_is_on, |
| 1303 | .recalc_rate = bcm2835_clock_get_rate, | 1355 | .recalc_rate = bcm2835_clock_get_rate, |
| 1304 | .set_rate = bcm2835_clock_set_rate, | 1356 | .set_rate = bcm2835_clock_set_rate, |
| 1305 | .round_rate = bcm2835_clock_round_rate, | 1357 | .determine_rate = bcm2835_clock_determine_rate, |
| 1358 | .set_parent = bcm2835_clock_set_parent, | ||
| 1359 | .get_parent = bcm2835_clock_get_parent, | ||
| 1306 | }; | 1360 | }; |
| 1307 | 1361 | ||
| 1308 | static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman, | 1362 | static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman, |
| @@ -1396,45 +1450,23 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman, | |||
| 1396 | { | 1450 | { |
| 1397 | struct bcm2835_clock *clock; | 1451 | struct bcm2835_clock *clock; |
| 1398 | struct clk_init_data init; | 1452 | struct clk_init_data init; |
| 1399 | const char *parent; | 1453 | const char *parents[1 << CM_SRC_BITS]; |
| 1454 | size_t i; | ||
| 1400 | 1455 | ||
| 1401 | /* | 1456 | /* |
| 1402 | * Most of the clock generators have a mux field, so we | 1457 | * Replace our "xosc" references with the oscillator's |
| 1403 | * instantiate a generic mux as our parent to handle it. | 1458 | * actual name. |
| 1404 | */ | 1459 | */ |
| 1405 | if (data->num_mux_parents) { | 1460 | for (i = 0; i < data->num_mux_parents; i++) { |
| 1406 | const char *parents[1 << CM_SRC_BITS]; | 1461 | if (strcmp(data->parents[i], "xosc") == 0) |
| 1407 | int i; | 1462 | parents[i] = cprman->osc_name; |
| 1408 | 1463 | else | |
| 1409 | parent = devm_kasprintf(cprman->dev, GFP_KERNEL, | 1464 | parents[i] = data->parents[i]; |
| 1410 | "mux_%s", data->name); | ||
| 1411 | if (!parent) | ||
| 1412 | return NULL; | ||
| 1413 | |||
| 1414 | /* | ||
| 1415 | * Replace our "xosc" references with the oscillator's | ||
| 1416 | * actual name. | ||
| 1417 | */ | ||
| 1418 | for (i = 0; i < data->num_mux_parents; i++) { | ||
| 1419 | if (strcmp(data->parents[i], "xosc") == 0) | ||
| 1420 | parents[i] = cprman->osc_name; | ||
| 1421 | else | ||
| 1422 | parents[i] = data->parents[i]; | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | clk_register_mux(cprman->dev, parent, | ||
| 1426 | parents, data->num_mux_parents, | ||
| 1427 | CLK_SET_RATE_PARENT, | ||
| 1428 | cprman->regs + data->ctl_reg, | ||
| 1429 | CM_SRC_SHIFT, CM_SRC_BITS, | ||
| 1430 | 0, &cprman->regs_lock); | ||
| 1431 | } else { | ||
| 1432 | parent = data->parents[0]; | ||
| 1433 | } | 1465 | } |
| 1434 | 1466 | ||
| 1435 | memset(&init, 0, sizeof(init)); | 1467 | memset(&init, 0, sizeof(init)); |
| 1436 | init.parent_names = &parent; | 1468 | init.parent_names = parents; |
| 1437 | init.num_parents = 1; | 1469 | init.num_parents = data->num_mux_parents; |
| 1438 | init.name = data->name; | 1470 | init.name = data->name; |
| 1439 | init.flags = CLK_IGNORE_UNUSED; | 1471 | init.flags = CLK_IGNORE_UNUSED; |
| 1440 | 1472 | ||
