|
8 | 8 | #include <linux/of_device.h>
|
9 | 9 | #include <linux/platform_device.h>
|
10 | 10 | #include <linux/regmap.h>
|
| 11 | +#include <linux/reset-controller.h> |
11 | 12 | #include <linux/slab.h>
|
12 | 13 | #include <linux/spinlock.h>
|
13 | 14 |
|
@@ -267,6 +268,68 @@ static const struct clk_ops aspeed_clk_gate_ops = {
|
267 | 268 | .is_enabled = aspeed_clk_is_enabled,
|
268 | 269 | };
|
269 | 270 |
|
| 271 | +/** |
| 272 | + * struct aspeed_reset - Aspeed reset controller |
| 273 | + * @map: regmap to access the containing system controller |
| 274 | + * @rcdev: reset controller device |
| 275 | + */ |
| 276 | +struct aspeed_reset { |
| 277 | + struct regmap *map; |
| 278 | + struct reset_controller_dev rcdev; |
| 279 | +}; |
| 280 | + |
| 281 | +#define to_aspeed_reset(p) container_of((p), struct aspeed_reset, rcdev) |
| 282 | + |
| 283 | +static const u8 aspeed_resets[] = { |
| 284 | + [ASPEED_RESET_XDMA] = 25, |
| 285 | + [ASPEED_RESET_MCTP] = 24, |
| 286 | + [ASPEED_RESET_ADC] = 23, |
| 287 | + [ASPEED_RESET_JTAG_MASTER] = 22, |
| 288 | + [ASPEED_RESET_MIC] = 18, |
| 289 | + [ASPEED_RESET_PWM] = 9, |
| 290 | + [ASPEED_RESET_PCIVGA] = 8, |
| 291 | + [ASPEED_RESET_I2C] = 2, |
| 292 | + [ASPEED_RESET_AHB] = 1, |
| 293 | +}; |
| 294 | + |
| 295 | +static int aspeed_reset_deassert(struct reset_controller_dev *rcdev, |
| 296 | + unsigned long id) |
| 297 | +{ |
| 298 | + struct aspeed_reset *ar = to_aspeed_reset(rcdev); |
| 299 | + u32 rst = BIT(aspeed_resets[id]); |
| 300 | + |
| 301 | + return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, 0); |
| 302 | +} |
| 303 | + |
| 304 | +static int aspeed_reset_assert(struct reset_controller_dev *rcdev, |
| 305 | + unsigned long id) |
| 306 | +{ |
| 307 | + struct aspeed_reset *ar = to_aspeed_reset(rcdev); |
| 308 | + u32 rst = BIT(aspeed_resets[id]); |
| 309 | + |
| 310 | + return regmap_update_bits(ar->map, ASPEED_RESET_CTRL, rst, rst); |
| 311 | +} |
| 312 | + |
| 313 | +static int aspeed_reset_status(struct reset_controller_dev *rcdev, |
| 314 | + unsigned long id) |
| 315 | +{ |
| 316 | + struct aspeed_reset *ar = to_aspeed_reset(rcdev); |
| 317 | + u32 val, rst = BIT(aspeed_resets[id]); |
| 318 | + int ret; |
| 319 | + |
| 320 | + ret = regmap_read(ar->map, ASPEED_RESET_CTRL, &val); |
| 321 | + if (ret) |
| 322 | + return ret; |
| 323 | + |
| 324 | + return !!(val & rst); |
| 325 | +} |
| 326 | + |
| 327 | +static const struct reset_control_ops aspeed_reset_ops = { |
| 328 | + .assert = aspeed_reset_assert, |
| 329 | + .deassert = aspeed_reset_deassert, |
| 330 | + .status = aspeed_reset_status, |
| 331 | +}; |
| 332 | + |
270 | 333 | static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev,
|
271 | 334 | const char *name, const char *parent_name, unsigned long flags,
|
272 | 335 | struct regmap *map, u8 clock_idx, u8 reset_idx,
|
@@ -308,17 +371,34 @@ static int aspeed_clk_probe(struct platform_device *pdev)
|
308 | 371 | {
|
309 | 372 | const struct aspeed_clk_soc_data *soc_data;
|
310 | 373 | struct device *dev = &pdev->dev;
|
| 374 | + struct aspeed_reset *ar; |
311 | 375 | struct regmap *map;
|
312 | 376 | struct clk_hw *hw;
|
313 | 377 | u32 val, rate;
|
314 |
| - int i; |
| 378 | + int i, ret; |
315 | 379 |
|
316 | 380 | map = syscon_node_to_regmap(dev->of_node);
|
317 | 381 | if (IS_ERR(map)) {
|
318 | 382 | dev_err(dev, "no syscon regmap\n");
|
319 | 383 | return PTR_ERR(map);
|
320 | 384 | }
|
321 | 385 |
|
| 386 | + ar = devm_kzalloc(dev, sizeof(*ar), GFP_KERNEL); |
| 387 | + if (!ar) |
| 388 | + return -ENOMEM; |
| 389 | + |
| 390 | + ar->map = map; |
| 391 | + ar->rcdev.owner = THIS_MODULE; |
| 392 | + ar->rcdev.nr_resets = ARRAY_SIZE(aspeed_resets); |
| 393 | + ar->rcdev.ops = &aspeed_reset_ops; |
| 394 | + ar->rcdev.of_node = dev->of_node; |
| 395 | + |
| 396 | + ret = devm_reset_controller_register(dev, &ar->rcdev); |
| 397 | + if (ret) { |
| 398 | + dev_err(dev, "could not register reset controller\n"); |
| 399 | + return ret; |
| 400 | + } |
| 401 | + |
322 | 402 | /* SoC generations share common layouts but have different divisors */
|
323 | 403 | soc_data = of_device_get_match_data(dev);
|
324 | 404 | if (!soc_data) {
|
|
0 commit comments