clk: ti: add support for register read-modify-write low-level operation
authorTero Kristo <t-kristo@ti.com>
Wed, 26 Jul 2017 13:47:27 +0000 (16:47 +0300)
committerTero Kristo <t-kristo@ti.com>
Thu, 8 Mar 2018 09:42:04 +0000 (11:42 +0200)
Useful for changing few bits on a register, this makes sure for example
that the operation is done atomically in case of syscon.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
drivers/clk/ti/clk.c
include/linux/clk/ti.h

index f4d6802..4efa2c9 100644 (file)
@@ -55,6 +55,29 @@ static void clk_memmap_writel(u32 val, const struct clk_omap_reg *reg)
                writel_relaxed(val, io->mem + reg->offset);
 }
 
+static void _clk_rmw(u32 val, u32 mask, void __iomem *ptr)
+{
+       u32 v;
+
+       v = readl_relaxed(ptr);
+       v &= ~mask;
+       v |= val;
+       writel_relaxed(v, ptr);
+}
+
+static void clk_memmap_rmw(u32 val, u32 mask, const struct clk_omap_reg *reg)
+{
+       struct clk_iomap *io = clk_memmaps[reg->index];
+
+       if (reg->ptr) {
+               _clk_rmw(val, mask, reg->ptr);
+       } else if (io->regmap) {
+               regmap_update_bits(io->regmap, reg->offset, mask, val);
+       } else {
+               _clk_rmw(val, mask, io->mem + reg->offset);
+       }
+}
+
 static u32 clk_memmap_readl(const struct clk_omap_reg *reg)
 {
        u32 val;
@@ -89,6 +112,7 @@ int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops)
        ti_clk_ll_ops = ops;
        ops->clk_readl = clk_memmap_readl;
        ops->clk_writel = clk_memmap_writel;
+       ops->clk_rmw = clk_memmap_rmw;
 
        return 0;
 }
index d18da83..9e86114 100644 (file)
@@ -211,6 +211,7 @@ enum {
  * struct ti_clk_ll_ops - low-level ops for clocks
  * @clk_readl: pointer to register read function
  * @clk_writel: pointer to register write function
+ * @clk_rmw: pointer to register read-modify-write function
  * @clkdm_clk_enable: pointer to clockdomain enable function
  * @clkdm_clk_disable: pointer to clockdomain disable function
  * @clkdm_lookup: pointer to clockdomain lookup function
@@ -226,6 +227,7 @@ enum {
 struct ti_clk_ll_ops {
        u32     (*clk_readl)(const struct clk_omap_reg *reg);
        void    (*clk_writel)(u32 val, const struct clk_omap_reg *reg);
+       void    (*clk_rmw)(u32 val, u32 mask, const struct clk_omap_reg *reg);
        int     (*clkdm_clk_enable)(struct clockdomain *clkdm, struct clk *clk);
        int     (*clkdm_clk_disable)(struct clockdomain *clkdm,
                                     struct clk *clk);