diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile index ecf0b09bb49a..baf22bf1df9a 100644 --- a/drivers/clk/msm/Makefile +++ b/drivers/clk/msm/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_COMMON_CLK_MSM) += clock-pll.o obj-$(CONFIG_COMMON_CLK_MSM) += clock-alpha-pll.o obj-$(CONFIG_COMMON_CLK_MSM) += clock-rpm.o obj-$(CONFIG_COMMON_CLK_MSM) += clock-voter.o +obj-$(CONFIG_COMMON_CLK_MSM) += reset.o obj-$(CONFIG_MSM_CLK_CONTROLLER_V2) += msm-clock-controller.o diff --git a/drivers/clk/msm/reset.c b/drivers/clk/msm/reset.c new file mode 100644 index 000000000000..41e0357aea3e --- /dev/null +++ b/drivers/clk/msm/reset.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "reset.h" + +static int msm_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + rcdev->ops->assert(rcdev, id); + udelay(1); + rcdev->ops->deassert(rcdev, id); + return 0; +} + +static int +msm_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct msm_reset_controller *rst; + const struct msm_reset_map *map; + u32 regval; + + rst = to_msm_reset_controller(rcdev); + map = &rst->reset_map[id]; + + regval = readl_relaxed(rst->base + map->reg); + regval |= BIT(map->bit); + writel_relaxed(regval, rst->base + map->reg); + + return 0; +} + +static int +msm_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct msm_reset_controller *rst; + const struct msm_reset_map *map; + u32 regval; + + rst = to_msm_reset_controller(rcdev); + map = &rst->reset_map[id]; + + regval = readl_relaxed(rst->base + map->reg); + regval &= ~BIT(map->bit); + writel_relaxed(regval, rst->base + map->reg); + + return 0; +} + +struct reset_control_ops msm_reset_ops = { + .reset = msm_reset, + .assert = msm_reset_assert, + .deassert = msm_reset_deassert, +}; +EXPORT_SYMBOL_GPL(msm_reset_ops); + +int msm_reset_controller_register(struct platform_device *pdev, + const struct msm_reset_map *map, unsigned int num_resets, + void __iomem *virt_base) +{ + struct msm_reset_controller *reset; + int ret = 0; + + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); + if (!reset) + return -ENOMEM; + + reset->rcdev.of_node = pdev->dev.of_node; + reset->rcdev.ops = &msm_reset_ops; + reset->rcdev.owner = pdev->dev.driver->owner; + reset->rcdev.nr_resets = num_resets; + reset->reset_map = map; + reset->base = virt_base; + + ret = reset_controller_register(&reset->rcdev); + if (ret) + dev_err(&pdev->dev, "Failed to register with reset controller\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(msm_reset_controller_register); diff --git a/drivers/clk/msm/reset.h b/drivers/clk/msm/reset.h new file mode 100644 index 000000000000..538a432fed60 --- /dev/null +++ b/drivers/clk/msm/reset.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __DRIVERS_CLK_RESET_H +#define __DRIVERS_CLK_RESET_H + +#include +#include + +struct msm_reset_map { + unsigned int reg; + u8 bit; +}; + +struct msm_reset_controller { + const struct msm_reset_map *reset_map; + struct reset_controller_dev rcdev; + void __iomem *base; +}; + +#define to_msm_reset_controller(r) \ + container_of(r, struct msm_reset_controller, rcdev) + +extern struct reset_control_ops msm_reset_ops; + +int msm_reset_controller_register(struct platform_device *pdev, + const struct msm_reset_map *map, unsigned int nr_resets, + void __iomem *virt_base); +#endif