mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
mfd: syscon: Allow reset control for syscon devices
Simple syscon devices may require deassertion of a reset signal in order to access their register set. Rather than requiring a custom driver to implement this, we can use the generic "resets" specifiers to link a reset line to the syscon. This change adds an optional reset line to the syscon device description, and deasserts the reset if detected. Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au> Reviewed-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Lee Jones <lee@kernel.org> Link: https://lore.kernel.org/r/20230105005010.124948-3-jk@codeconstruct.com.au
This commit is contained in:
parent
0f4d261989
commit
7d1e3bd948
@ -20,6 +20,7 @@
|
||||
#include <linux/platform_data/syscon.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@ -31,6 +32,7 @@ static LIST_HEAD(syscon_list);
|
||||
struct syscon {
|
||||
struct device_node *np;
|
||||
struct regmap *regmap;
|
||||
struct reset_control *reset;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
@ -40,7 +42,7 @@ static const struct regmap_config syscon_regmap_config = {
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
|
||||
static struct syscon *of_syscon_register(struct device_node *np, bool check_res)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct syscon *syscon;
|
||||
@ -50,6 +52,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
|
||||
int ret;
|
||||
struct regmap_config syscon_config = syscon_regmap_config;
|
||||
struct resource res;
|
||||
struct reset_control *reset;
|
||||
|
||||
syscon = kzalloc(sizeof(*syscon), GFP_KERNEL);
|
||||
if (!syscon)
|
||||
@ -114,7 +117,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
|
||||
goto err_regmap;
|
||||
}
|
||||
|
||||
if (check_clk) {
|
||||
if (check_res) {
|
||||
clk = of_clk_get(np, 0);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
@ -124,8 +127,18 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
|
||||
} else {
|
||||
ret = regmap_mmio_attach_clk(regmap, clk);
|
||||
if (ret)
|
||||
goto err_attach;
|
||||
goto err_attach_clk;
|
||||
}
|
||||
|
||||
reset = of_reset_control_get_optional_exclusive(np, NULL);
|
||||
if (IS_ERR(reset)) {
|
||||
ret = PTR_ERR(reset);
|
||||
goto err_attach_clk;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(reset);
|
||||
if (ret)
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
syscon->regmap = regmap;
|
||||
@ -137,7 +150,9 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
|
||||
|
||||
return syscon;
|
||||
|
||||
err_attach:
|
||||
err_reset:
|
||||
reset_control_put(reset);
|
||||
err_attach_clk:
|
||||
if (!IS_ERR(clk))
|
||||
clk_put(clk);
|
||||
err_clk:
|
||||
@ -150,7 +165,7 @@ err_map:
|
||||
}
|
||||
|
||||
static struct regmap *device_node_get_regmap(struct device_node *np,
|
||||
bool check_clk)
|
||||
bool check_res)
|
||||
{
|
||||
struct syscon *entry, *syscon = NULL;
|
||||
|
||||
@ -165,7 +180,7 @@ static struct regmap *device_node_get_regmap(struct device_node *np,
|
||||
spin_unlock(&syscon_list_slock);
|
||||
|
||||
if (!syscon)
|
||||
syscon = of_syscon_register(np, check_clk);
|
||||
syscon = of_syscon_register(np, check_res);
|
||||
|
||||
if (IS_ERR(syscon))
|
||||
return ERR_CAST(syscon);
|
||||
|
Loading…
Reference in New Issue
Block a user