137613fa5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
237613fa5SGreg Kroah-Hartman //
337613fa5SGreg Kroah-Hartman // Register map access API - MMIO support
437613fa5SGreg Kroah-Hartman //
537613fa5SGreg Kroah-Hartman // Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
645f5ff81SStephen Warren
7878ec67bSPhilipp Zabel #include <linux/clk.h>
845f5ff81SStephen Warren #include <linux/err.h>
945f5ff81SStephen Warren #include <linux/io.h>
1045f5ff81SStephen Warren #include <linux/module.h>
1145f5ff81SStephen Warren #include <linux/regmap.h>
1245f5ff81SStephen Warren #include <linux/slab.h>
13400dceb6SAndy Shevchenko #include <linux/swab.h>
1445f5ff81SStephen Warren
150dbdb76cSMark Brown #include "internal.h"
160dbdb76cSMark Brown
1745f5ff81SStephen Warren struct regmap_mmio_context {
1845f5ff81SStephen Warren void __iomem *regs;
19d63aa09fSJinchao Wang unsigned int val_bytes;
2081c0386cSLinus Walleij bool big_endian;
2131895662SMaxime Ripard
2231895662SMaxime Ripard bool attached_clk;
23878ec67bSPhilipp Zabel struct clk *clk;
2445f5ff81SStephen Warren
25922a9f93SMark Brown void (*reg_write)(struct regmap_mmio_context *ctx,
26922a9f93SMark Brown unsigned int reg, unsigned int val);
27922a9f93SMark Brown unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
28922a9f93SMark Brown unsigned int reg);
29922a9f93SMark Brown };
3041b0c2c9SXiubo Li
regmap_mmio_regbits_check(size_t reg_bits)31451485baSXiubo Li static int regmap_mmio_regbits_check(size_t reg_bits)
32451485baSXiubo Li {
33451485baSXiubo Li switch (reg_bits) {
34451485baSXiubo Li case 8:
35451485baSXiubo Li case 16:
36451485baSXiubo Li case 32:
37451485baSXiubo Li return 0;
38451485baSXiubo Li default:
39451485baSXiubo Li return -EINVAL;
40451485baSXiubo Li }
41451485baSXiubo Li }
42451485baSXiubo Li
regmap_mmio_get_min_stride(size_t val_bits)4375fb0aaeSXiubo Li static int regmap_mmio_get_min_stride(size_t val_bits)
4475fb0aaeSXiubo Li {
4575fb0aaeSXiubo Li int min_stride;
4675fb0aaeSXiubo Li
4775fb0aaeSXiubo Li switch (val_bits) {
4875fb0aaeSXiubo Li case 8:
4975fb0aaeSXiubo Li /* The core treats 0 as 1 */
5075fb0aaeSXiubo Li min_stride = 0;
5101ed2307SColin Ian King break;
5275fb0aaeSXiubo Li case 16:
5375fb0aaeSXiubo Li min_stride = 2;
5475fb0aaeSXiubo Li break;
5575fb0aaeSXiubo Li case 32:
5675fb0aaeSXiubo Li min_stride = 4;
5775fb0aaeSXiubo Li break;
5875fb0aaeSXiubo Li default:
5975fb0aaeSXiubo Li return -EINVAL;
6075fb0aaeSXiubo Li }
6175fb0aaeSXiubo Li
6275fb0aaeSXiubo Li return min_stride;
6375fb0aaeSXiubo Li }
6475fb0aaeSXiubo Li
regmap_mmio_write8(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)65922a9f93SMark Brown static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
66922a9f93SMark Brown unsigned int reg,
67922a9f93SMark Brown unsigned int val)
6841b0c2c9SXiubo Li {
69922a9f93SMark Brown writeb(val, ctx->regs + reg);
7041b0c2c9SXiubo Li }
7141b0c2c9SXiubo Li
regmap_mmio_write8_relaxed(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)726e1e90ecSAdrian Ratiu static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx,
736e1e90ecSAdrian Ratiu unsigned int reg,
746e1e90ecSAdrian Ratiu unsigned int val)
756e1e90ecSAdrian Ratiu {
766e1e90ecSAdrian Ratiu writeb_relaxed(val, ctx->regs + reg);
776e1e90ecSAdrian Ratiu }
786e1e90ecSAdrian Ratiu
regmap_mmio_iowrite8(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)7993ce5576SAndy Shevchenko static void regmap_mmio_iowrite8(struct regmap_mmio_context *ctx,
8093ce5576SAndy Shevchenko unsigned int reg, unsigned int val)
8193ce5576SAndy Shevchenko {
8293ce5576SAndy Shevchenko iowrite8(val, ctx->regs + reg);
8393ce5576SAndy Shevchenko }
8493ce5576SAndy Shevchenko
regmap_mmio_write16le(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)85922a9f93SMark Brown static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
86922a9f93SMark Brown unsigned int reg,
87922a9f93SMark Brown unsigned int val)
8888cb32c6SXiubo Li {
89922a9f93SMark Brown writew(val, ctx->regs + reg);
90922a9f93SMark Brown }
91922a9f93SMark Brown
regmap_mmio_write16le_relaxed(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)926e1e90ecSAdrian Ratiu static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx,
936e1e90ecSAdrian Ratiu unsigned int reg,
946e1e90ecSAdrian Ratiu unsigned int val)
956e1e90ecSAdrian Ratiu {
966e1e90ecSAdrian Ratiu writew_relaxed(val, ctx->regs + reg);
976e1e90ecSAdrian Ratiu }
986e1e90ecSAdrian Ratiu
regmap_mmio_iowrite16le(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)9993ce5576SAndy Shevchenko static void regmap_mmio_iowrite16le(struct regmap_mmio_context *ctx,
10093ce5576SAndy Shevchenko unsigned int reg, unsigned int val)
10193ce5576SAndy Shevchenko {
10293ce5576SAndy Shevchenko iowrite16(val, ctx->regs + reg);
10393ce5576SAndy Shevchenko }
10493ce5576SAndy Shevchenko
regmap_mmio_write16be(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)105922a9f93SMark Brown static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
106922a9f93SMark Brown unsigned int reg,
107922a9f93SMark Brown unsigned int val)
108922a9f93SMark Brown {
1097e7ba58cSAndy Shevchenko writew(swab16(val), ctx->regs + reg);
110922a9f93SMark Brown }
111922a9f93SMark Brown
regmap_mmio_iowrite16be(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)11293ce5576SAndy Shevchenko static void regmap_mmio_iowrite16be(struct regmap_mmio_context *ctx,
11393ce5576SAndy Shevchenko unsigned int reg, unsigned int val)
11493ce5576SAndy Shevchenko {
11593ce5576SAndy Shevchenko iowrite16be(val, ctx->regs + reg);
11693ce5576SAndy Shevchenko }
11793ce5576SAndy Shevchenko
regmap_mmio_write32le(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)118922a9f93SMark Brown static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
119922a9f93SMark Brown unsigned int reg,
120922a9f93SMark Brown unsigned int val)
121922a9f93SMark Brown {
122922a9f93SMark Brown writel(val, ctx->regs + reg);
123922a9f93SMark Brown }
124922a9f93SMark Brown
regmap_mmio_write32le_relaxed(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)1256e1e90ecSAdrian Ratiu static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx,
1266e1e90ecSAdrian Ratiu unsigned int reg,
1276e1e90ecSAdrian Ratiu unsigned int val)
1286e1e90ecSAdrian Ratiu {
1296e1e90ecSAdrian Ratiu writel_relaxed(val, ctx->regs + reg);
1306e1e90ecSAdrian Ratiu }
1316e1e90ecSAdrian Ratiu
regmap_mmio_iowrite32le(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)13293ce5576SAndy Shevchenko static void regmap_mmio_iowrite32le(struct regmap_mmio_context *ctx,
13393ce5576SAndy Shevchenko unsigned int reg, unsigned int val)
13493ce5576SAndy Shevchenko {
13593ce5576SAndy Shevchenko iowrite32(val, ctx->regs + reg);
13693ce5576SAndy Shevchenko }
13793ce5576SAndy Shevchenko
regmap_mmio_write32be(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)138922a9f93SMark Brown static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
139922a9f93SMark Brown unsigned int reg,
140922a9f93SMark Brown unsigned int val)
141922a9f93SMark Brown {
1427e7ba58cSAndy Shevchenko writel(swab32(val), ctx->regs + reg);
143922a9f93SMark Brown }
144922a9f93SMark Brown
regmap_mmio_iowrite32be(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)14593ce5576SAndy Shevchenko static void regmap_mmio_iowrite32be(struct regmap_mmio_context *ctx,
14693ce5576SAndy Shevchenko unsigned int reg, unsigned int val)
14793ce5576SAndy Shevchenko {
14893ce5576SAndy Shevchenko iowrite32be(val, ctx->regs + reg);
14993ce5576SAndy Shevchenko }
15093ce5576SAndy Shevchenko
regmap_mmio_write(void * context,unsigned int reg,unsigned int val)151922a9f93SMark Brown static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
15245f5ff81SStephen Warren {
15345f5ff81SStephen Warren struct regmap_mmio_context *ctx = context;
154878ec67bSPhilipp Zabel int ret;
15545f5ff81SStephen Warren
1566b8e090eSStephen Warren if (!IS_ERR(ctx->clk)) {
157878ec67bSPhilipp Zabel ret = clk_enable(ctx->clk);
158878ec67bSPhilipp Zabel if (ret < 0)
159878ec67bSPhilipp Zabel return ret;
160878ec67bSPhilipp Zabel }
161878ec67bSPhilipp Zabel
162922a9f93SMark Brown ctx->reg_write(ctx, reg, val);
16345f5ff81SStephen Warren
1646b8e090eSStephen Warren if (!IS_ERR(ctx->clk))
165878ec67bSPhilipp Zabel clk_disable(ctx->clk);
166878ec67bSPhilipp Zabel
16745f5ff81SStephen Warren return 0;
16845f5ff81SStephen Warren }
16945f5ff81SStephen Warren
regmap_mmio_noinc_write(void * context,unsigned int reg,const void * val,size_t val_count)17081c0386cSLinus Walleij static int regmap_mmio_noinc_write(void *context, unsigned int reg,
17181c0386cSLinus Walleij const void *val, size_t val_count)
17281c0386cSLinus Walleij {
17381c0386cSLinus Walleij struct regmap_mmio_context *ctx = context;
17481c0386cSLinus Walleij int ret = 0;
17581c0386cSLinus Walleij int i;
17681c0386cSLinus Walleij
17781c0386cSLinus Walleij if (!IS_ERR(ctx->clk)) {
17881c0386cSLinus Walleij ret = clk_enable(ctx->clk);
17981c0386cSLinus Walleij if (ret < 0)
18081c0386cSLinus Walleij return ret;
18181c0386cSLinus Walleij }
18281c0386cSLinus Walleij
18381c0386cSLinus Walleij /*
18481c0386cSLinus Walleij * There are no native, assembly-optimized write single register
18581c0386cSLinus Walleij * operations for big endian, so fall back to emulation if this
18681c0386cSLinus Walleij * is needed. (Single bytes are fine, they are not affected by
18781c0386cSLinus Walleij * endianness.)
18881c0386cSLinus Walleij */
18981c0386cSLinus Walleij if (ctx->big_endian && (ctx->val_bytes > 1)) {
19081c0386cSLinus Walleij switch (ctx->val_bytes) {
19181c0386cSLinus Walleij case 2:
19281c0386cSLinus Walleij {
19381c0386cSLinus Walleij const u16 *valp = (const u16 *)val;
19481c0386cSLinus Walleij for (i = 0; i < val_count; i++)
19581c0386cSLinus Walleij writew(swab16(valp[i]), ctx->regs + reg);
19681c0386cSLinus Walleij goto out_clk;
19781c0386cSLinus Walleij }
19881c0386cSLinus Walleij case 4:
19981c0386cSLinus Walleij {
20081c0386cSLinus Walleij const u32 *valp = (const u32 *)val;
20181c0386cSLinus Walleij for (i = 0; i < val_count; i++)
20281c0386cSLinus Walleij writel(swab32(valp[i]), ctx->regs + reg);
20381c0386cSLinus Walleij goto out_clk;
20481c0386cSLinus Walleij }
20581c0386cSLinus Walleij default:
20681c0386cSLinus Walleij ret = -EINVAL;
20781c0386cSLinus Walleij goto out_clk;
20881c0386cSLinus Walleij }
20981c0386cSLinus Walleij }
21081c0386cSLinus Walleij
21181c0386cSLinus Walleij switch (ctx->val_bytes) {
21281c0386cSLinus Walleij case 1:
21381c0386cSLinus Walleij writesb(ctx->regs + reg, (const u8 *)val, val_count);
21481c0386cSLinus Walleij break;
21581c0386cSLinus Walleij case 2:
21681c0386cSLinus Walleij writesw(ctx->regs + reg, (const u16 *)val, val_count);
21781c0386cSLinus Walleij break;
21881c0386cSLinus Walleij case 4:
21981c0386cSLinus Walleij writesl(ctx->regs + reg, (const u32 *)val, val_count);
22081c0386cSLinus Walleij break;
22181c0386cSLinus Walleij default:
22281c0386cSLinus Walleij ret = -EINVAL;
22381c0386cSLinus Walleij break;
22481c0386cSLinus Walleij }
22581c0386cSLinus Walleij
22681c0386cSLinus Walleij out_clk:
22781c0386cSLinus Walleij if (!IS_ERR(ctx->clk))
22881c0386cSLinus Walleij clk_disable(ctx->clk);
22981c0386cSLinus Walleij
23081c0386cSLinus Walleij return ret;
23181c0386cSLinus Walleij }
23281c0386cSLinus Walleij
regmap_mmio_read8(struct regmap_mmio_context * ctx,unsigned int reg)233922a9f93SMark Brown static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
234922a9f93SMark Brown unsigned int reg)
23545f5ff81SStephen Warren {
236922a9f93SMark Brown return readb(ctx->regs + reg);
23745f5ff81SStephen Warren }
23845f5ff81SStephen Warren
regmap_mmio_read8_relaxed(struct regmap_mmio_context * ctx,unsigned int reg)2396e1e90ecSAdrian Ratiu static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx,
2406e1e90ecSAdrian Ratiu unsigned int reg)
2416e1e90ecSAdrian Ratiu {
2426e1e90ecSAdrian Ratiu return readb_relaxed(ctx->regs + reg);
2436e1e90ecSAdrian Ratiu }
2446e1e90ecSAdrian Ratiu
regmap_mmio_ioread8(struct regmap_mmio_context * ctx,unsigned int reg)24593ce5576SAndy Shevchenko static unsigned int regmap_mmio_ioread8(struct regmap_mmio_context *ctx,
24693ce5576SAndy Shevchenko unsigned int reg)
24793ce5576SAndy Shevchenko {
24893ce5576SAndy Shevchenko return ioread8(ctx->regs + reg);
24993ce5576SAndy Shevchenko }
25093ce5576SAndy Shevchenko
regmap_mmio_read16le(struct regmap_mmio_context * ctx,unsigned int reg)251922a9f93SMark Brown static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
252922a9f93SMark Brown unsigned int reg)
253922a9f93SMark Brown {
254922a9f93SMark Brown return readw(ctx->regs + reg);
255922a9f93SMark Brown }
256922a9f93SMark Brown
regmap_mmio_read16le_relaxed(struct regmap_mmio_context * ctx,unsigned int reg)2576e1e90ecSAdrian Ratiu static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx,
2586e1e90ecSAdrian Ratiu unsigned int reg)
2596e1e90ecSAdrian Ratiu {
2606e1e90ecSAdrian Ratiu return readw_relaxed(ctx->regs + reg);
2616e1e90ecSAdrian Ratiu }
2626e1e90ecSAdrian Ratiu
regmap_mmio_ioread16le(struct regmap_mmio_context * ctx,unsigned int reg)26393ce5576SAndy Shevchenko static unsigned int regmap_mmio_ioread16le(struct regmap_mmio_context *ctx,
26493ce5576SAndy Shevchenko unsigned int reg)
26593ce5576SAndy Shevchenko {
26693ce5576SAndy Shevchenko return ioread16(ctx->regs + reg);
26793ce5576SAndy Shevchenko }
26893ce5576SAndy Shevchenko
regmap_mmio_read16be(struct regmap_mmio_context * ctx,unsigned int reg)269922a9f93SMark Brown static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
270922a9f93SMark Brown unsigned int reg)
271922a9f93SMark Brown {
2727e7ba58cSAndy Shevchenko return swab16(readw(ctx->regs + reg));
273922a9f93SMark Brown }
274922a9f93SMark Brown
regmap_mmio_ioread16be(struct regmap_mmio_context * ctx,unsigned int reg)27593ce5576SAndy Shevchenko static unsigned int regmap_mmio_ioread16be(struct regmap_mmio_context *ctx,
27693ce5576SAndy Shevchenko unsigned int reg)
27793ce5576SAndy Shevchenko {
27893ce5576SAndy Shevchenko return ioread16be(ctx->regs + reg);
27993ce5576SAndy Shevchenko }
28093ce5576SAndy Shevchenko
regmap_mmio_read32le(struct regmap_mmio_context * ctx,unsigned int reg)281922a9f93SMark Brown static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
282922a9f93SMark Brown unsigned int reg)
283922a9f93SMark Brown {
284922a9f93SMark Brown return readl(ctx->regs + reg);
285922a9f93SMark Brown }
286922a9f93SMark Brown
regmap_mmio_read32le_relaxed(struct regmap_mmio_context * ctx,unsigned int reg)2876e1e90ecSAdrian Ratiu static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx,
2886e1e90ecSAdrian Ratiu unsigned int reg)
2896e1e90ecSAdrian Ratiu {
2906e1e90ecSAdrian Ratiu return readl_relaxed(ctx->regs + reg);
2916e1e90ecSAdrian Ratiu }
2926e1e90ecSAdrian Ratiu
regmap_mmio_ioread32le(struct regmap_mmio_context * ctx,unsigned int reg)29393ce5576SAndy Shevchenko static unsigned int regmap_mmio_ioread32le(struct regmap_mmio_context *ctx,
29493ce5576SAndy Shevchenko unsigned int reg)
29593ce5576SAndy Shevchenko {
29693ce5576SAndy Shevchenko return ioread32(ctx->regs + reg);
29793ce5576SAndy Shevchenko }
29893ce5576SAndy Shevchenko
regmap_mmio_read32be(struct regmap_mmio_context * ctx,unsigned int reg)299922a9f93SMark Brown static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
300922a9f93SMark Brown unsigned int reg)
301922a9f93SMark Brown {
3027e7ba58cSAndy Shevchenko return swab32(readl(ctx->regs + reg));
303922a9f93SMark Brown }
304922a9f93SMark Brown
regmap_mmio_ioread32be(struct regmap_mmio_context * ctx,unsigned int reg)30593ce5576SAndy Shevchenko static unsigned int regmap_mmio_ioread32be(struct regmap_mmio_context *ctx,
30693ce5576SAndy Shevchenko unsigned int reg)
30793ce5576SAndy Shevchenko {
30893ce5576SAndy Shevchenko return ioread32be(ctx->regs + reg);
30993ce5576SAndy Shevchenko }
31093ce5576SAndy Shevchenko
regmap_mmio_read(void * context,unsigned int reg,unsigned int * val)311922a9f93SMark Brown static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
31245f5ff81SStephen Warren {
31345f5ff81SStephen Warren struct regmap_mmio_context *ctx = context;
314878ec67bSPhilipp Zabel int ret;
31545f5ff81SStephen Warren
3166b8e090eSStephen Warren if (!IS_ERR(ctx->clk)) {
317878ec67bSPhilipp Zabel ret = clk_enable(ctx->clk);
318878ec67bSPhilipp Zabel if (ret < 0)
319878ec67bSPhilipp Zabel return ret;
320878ec67bSPhilipp Zabel }
321878ec67bSPhilipp Zabel
322922a9f93SMark Brown *val = ctx->reg_read(ctx, reg);
32345f5ff81SStephen Warren
3246b8e090eSStephen Warren if (!IS_ERR(ctx->clk))
325878ec67bSPhilipp Zabel clk_disable(ctx->clk);
326878ec67bSPhilipp Zabel
32745f5ff81SStephen Warren return 0;
32845f5ff81SStephen Warren }
32945f5ff81SStephen Warren
regmap_mmio_noinc_read(void * context,unsigned int reg,void * val,size_t val_count)33081c0386cSLinus Walleij static int regmap_mmio_noinc_read(void *context, unsigned int reg,
33181c0386cSLinus Walleij void *val, size_t val_count)
33281c0386cSLinus Walleij {
33381c0386cSLinus Walleij struct regmap_mmio_context *ctx = context;
33481c0386cSLinus Walleij int ret = 0;
33581c0386cSLinus Walleij
33681c0386cSLinus Walleij if (!IS_ERR(ctx->clk)) {
33781c0386cSLinus Walleij ret = clk_enable(ctx->clk);
33881c0386cSLinus Walleij if (ret < 0)
33981c0386cSLinus Walleij return ret;
34081c0386cSLinus Walleij }
34181c0386cSLinus Walleij
34281c0386cSLinus Walleij switch (ctx->val_bytes) {
34381c0386cSLinus Walleij case 1:
34481c0386cSLinus Walleij readsb(ctx->regs + reg, (u8 *)val, val_count);
34581c0386cSLinus Walleij break;
34681c0386cSLinus Walleij case 2:
34781c0386cSLinus Walleij readsw(ctx->regs + reg, (u16 *)val, val_count);
34881c0386cSLinus Walleij break;
34981c0386cSLinus Walleij case 4:
35081c0386cSLinus Walleij readsl(ctx->regs + reg, (u32 *)val, val_count);
35181c0386cSLinus Walleij break;
35281c0386cSLinus Walleij default:
35381c0386cSLinus Walleij ret = -EINVAL;
35481c0386cSLinus Walleij goto out_clk;
35581c0386cSLinus Walleij }
35681c0386cSLinus Walleij
35781c0386cSLinus Walleij /*
35881c0386cSLinus Walleij * There are no native, assembly-optimized write single register
35981c0386cSLinus Walleij * operations for big endian, so fall back to emulation if this
36081c0386cSLinus Walleij * is needed. (Single bytes are fine, they are not affected by
36181c0386cSLinus Walleij * endianness.)
36281c0386cSLinus Walleij */
36381c0386cSLinus Walleij if (ctx->big_endian && (ctx->val_bytes > 1)) {
36481c0386cSLinus Walleij switch (ctx->val_bytes) {
36581c0386cSLinus Walleij case 2:
366400dceb6SAndy Shevchenko swab16_array(val, val_count);
36781c0386cSLinus Walleij break;
36881c0386cSLinus Walleij case 4:
369400dceb6SAndy Shevchenko swab32_array(val, val_count);
37081c0386cSLinus Walleij break;
37181c0386cSLinus Walleij default:
37281c0386cSLinus Walleij ret = -EINVAL;
37381c0386cSLinus Walleij break;
37481c0386cSLinus Walleij }
37581c0386cSLinus Walleij }
37681c0386cSLinus Walleij
37781c0386cSLinus Walleij out_clk:
37881c0386cSLinus Walleij if (!IS_ERR(ctx->clk))
37981c0386cSLinus Walleij clk_disable(ctx->clk);
38081c0386cSLinus Walleij
38181c0386cSLinus Walleij return ret;
38281c0386cSLinus Walleij }
38381c0386cSLinus Walleij
38481c0386cSLinus Walleij
regmap_mmio_free_context(void * context)38545f5ff81SStephen Warren static void regmap_mmio_free_context(void *context)
38645f5ff81SStephen Warren {
387878ec67bSPhilipp Zabel struct regmap_mmio_context *ctx = context;
388878ec67bSPhilipp Zabel
3896b8e090eSStephen Warren if (!IS_ERR(ctx->clk)) {
390878ec67bSPhilipp Zabel clk_unprepare(ctx->clk);
391eb4a219dSJames Kelly if (!ctx->attached_clk)
392878ec67bSPhilipp Zabel clk_put(ctx->clk);
393878ec67bSPhilipp Zabel }
39445f5ff81SStephen Warren kfree(context);
39545f5ff81SStephen Warren }
39645f5ff81SStephen Warren
397922a9f93SMark Brown static const struct regmap_bus regmap_mmio = {
39845f5ff81SStephen Warren .fast_io = true,
399922a9f93SMark Brown .reg_write = regmap_mmio_write,
400922a9f93SMark Brown .reg_read = regmap_mmio_read,
40181c0386cSLinus Walleij .reg_noinc_write = regmap_mmio_noinc_write,
40281c0386cSLinus Walleij .reg_noinc_read = regmap_mmio_noinc_read,
40345f5ff81SStephen Warren .free_context = regmap_mmio_free_context,
4042ed94f6fSMark Brown .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
40545f5ff81SStephen Warren };
40645f5ff81SStephen Warren
regmap_mmio_gen_context(struct device * dev,const char * clk_id,void __iomem * regs,const struct regmap_config * config)407878ec67bSPhilipp Zabel static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
408878ec67bSPhilipp Zabel const char *clk_id,
409878ec67bSPhilipp Zabel void __iomem *regs,
41045f5ff81SStephen Warren const struct regmap_config *config)
41145f5ff81SStephen Warren {
41245f5ff81SStephen Warren struct regmap_mmio_context *ctx;
413f01ee60fSStephen Warren int min_stride;
414878ec67bSPhilipp Zabel int ret;
41545f5ff81SStephen Warren
416451485baSXiubo Li ret = regmap_mmio_regbits_check(config->reg_bits);
417451485baSXiubo Li if (ret)
418451485baSXiubo Li return ERR_PTR(ret);
41945f5ff81SStephen Warren
42045f5ff81SStephen Warren if (config->pad_bits)
42145f5ff81SStephen Warren return ERR_PTR(-EINVAL);
42245f5ff81SStephen Warren
42375fb0aaeSXiubo Li min_stride = regmap_mmio_get_min_stride(config->val_bits);
42475fb0aaeSXiubo Li if (min_stride < 0)
42575fb0aaeSXiubo Li return ERR_PTR(min_stride);
42645f5ff81SStephen Warren
427*e12ff287SMaxime Chevallier if (config->reg_stride && config->reg_stride < min_stride)
428f01ee60fSStephen Warren return ERR_PTR(-EINVAL);
429f01ee60fSStephen Warren
43093ce5576SAndy Shevchenko if (config->use_relaxed_mmio && config->io_port)
43193ce5576SAndy Shevchenko return ERR_PTR(-EINVAL);
43293ce5576SAndy Shevchenko
43346335119SDimitris Papastamos ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
43445f5ff81SStephen Warren if (!ctx)
43545f5ff81SStephen Warren return ERR_PTR(-ENOMEM);
43645f5ff81SStephen Warren
43745f5ff81SStephen Warren ctx->regs = regs;
43845f5ff81SStephen Warren ctx->val_bytes = config->val_bits / 8;
4396b8e090eSStephen Warren ctx->clk = ERR_PTR(-ENODEV);
44045f5ff81SStephen Warren
4410dbdb76cSMark Brown switch (regmap_get_val_endian(dev, ®map_mmio, config)) {
442922a9f93SMark Brown case REGMAP_ENDIAN_DEFAULT:
443922a9f93SMark Brown case REGMAP_ENDIAN_LITTLE:
444922a9f93SMark Brown #ifdef __LITTLE_ENDIAN
445922a9f93SMark Brown case REGMAP_ENDIAN_NATIVE:
446922a9f93SMark Brown #endif
447922a9f93SMark Brown switch (config->val_bits) {
448922a9f93SMark Brown case 8:
44993ce5576SAndy Shevchenko if (config->io_port) {
45093ce5576SAndy Shevchenko ctx->reg_read = regmap_mmio_ioread8;
45193ce5576SAndy Shevchenko ctx->reg_write = regmap_mmio_iowrite8;
45293ce5576SAndy Shevchenko } else if (config->use_relaxed_mmio) {
4536e1e90ecSAdrian Ratiu ctx->reg_read = regmap_mmio_read8_relaxed;
4546e1e90ecSAdrian Ratiu ctx->reg_write = regmap_mmio_write8_relaxed;
4556e1e90ecSAdrian Ratiu } else {
456922a9f93SMark Brown ctx->reg_read = regmap_mmio_read8;
457922a9f93SMark Brown ctx->reg_write = regmap_mmio_write8;
4586e1e90ecSAdrian Ratiu }
459922a9f93SMark Brown break;
460922a9f93SMark Brown case 16:
46193ce5576SAndy Shevchenko if (config->io_port) {
46293ce5576SAndy Shevchenko ctx->reg_read = regmap_mmio_ioread16le;
46393ce5576SAndy Shevchenko ctx->reg_write = regmap_mmio_iowrite16le;
46493ce5576SAndy Shevchenko } else if (config->use_relaxed_mmio) {
4656e1e90ecSAdrian Ratiu ctx->reg_read = regmap_mmio_read16le_relaxed;
4666e1e90ecSAdrian Ratiu ctx->reg_write = regmap_mmio_write16le_relaxed;
4676e1e90ecSAdrian Ratiu } else {
468922a9f93SMark Brown ctx->reg_read = regmap_mmio_read16le;
469922a9f93SMark Brown ctx->reg_write = regmap_mmio_write16le;
4706e1e90ecSAdrian Ratiu }
471922a9f93SMark Brown break;
472922a9f93SMark Brown case 32:
47393ce5576SAndy Shevchenko if (config->io_port) {
47493ce5576SAndy Shevchenko ctx->reg_read = regmap_mmio_ioread32le;
47593ce5576SAndy Shevchenko ctx->reg_write = regmap_mmio_iowrite32le;
47693ce5576SAndy Shevchenko } else if (config->use_relaxed_mmio) {
4776e1e90ecSAdrian Ratiu ctx->reg_read = regmap_mmio_read32le_relaxed;
4786e1e90ecSAdrian Ratiu ctx->reg_write = regmap_mmio_write32le_relaxed;
4796e1e90ecSAdrian Ratiu } else {
480922a9f93SMark Brown ctx->reg_read = regmap_mmio_read32le;
481922a9f93SMark Brown ctx->reg_write = regmap_mmio_write32le;
4826e1e90ecSAdrian Ratiu }
483922a9f93SMark Brown break;
484922a9f93SMark Brown default:
485922a9f93SMark Brown ret = -EINVAL;
486922a9f93SMark Brown goto err_free;
487922a9f93SMark Brown }
488922a9f93SMark Brown break;
489922a9f93SMark Brown case REGMAP_ENDIAN_BIG:
490922a9f93SMark Brown #ifdef __BIG_ENDIAN
491922a9f93SMark Brown case REGMAP_ENDIAN_NATIVE:
492922a9f93SMark Brown #endif
49381c0386cSLinus Walleij ctx->big_endian = true;
494922a9f93SMark Brown switch (config->val_bits) {
495922a9f93SMark Brown case 8:
49693ce5576SAndy Shevchenko if (config->io_port) {
49793ce5576SAndy Shevchenko ctx->reg_read = regmap_mmio_ioread8;
49893ce5576SAndy Shevchenko ctx->reg_write = regmap_mmio_iowrite8;
49993ce5576SAndy Shevchenko } else {
500922a9f93SMark Brown ctx->reg_read = regmap_mmio_read8;
501922a9f93SMark Brown ctx->reg_write = regmap_mmio_write8;
50293ce5576SAndy Shevchenko }
503922a9f93SMark Brown break;
504922a9f93SMark Brown case 16:
50593ce5576SAndy Shevchenko if (config->io_port) {
50693ce5576SAndy Shevchenko ctx->reg_read = regmap_mmio_ioread16be;
50793ce5576SAndy Shevchenko ctx->reg_write = regmap_mmio_iowrite16be;
50893ce5576SAndy Shevchenko } else {
509922a9f93SMark Brown ctx->reg_read = regmap_mmio_read16be;
510922a9f93SMark Brown ctx->reg_write = regmap_mmio_write16be;
51193ce5576SAndy Shevchenko }
512922a9f93SMark Brown break;
513922a9f93SMark Brown case 32:
51493ce5576SAndy Shevchenko if (config->io_port) {
51593ce5576SAndy Shevchenko ctx->reg_read = regmap_mmio_ioread32be;
51693ce5576SAndy Shevchenko ctx->reg_write = regmap_mmio_iowrite32be;
51793ce5576SAndy Shevchenko } else {
518922a9f93SMark Brown ctx->reg_read = regmap_mmio_read32be;
519922a9f93SMark Brown ctx->reg_write = regmap_mmio_write32be;
52093ce5576SAndy Shevchenko }
521922a9f93SMark Brown break;
522922a9f93SMark Brown default:
523922a9f93SMark Brown ret = -EINVAL;
524922a9f93SMark Brown goto err_free;
525922a9f93SMark Brown }
526922a9f93SMark Brown break;
527922a9f93SMark Brown default:
528922a9f93SMark Brown ret = -EINVAL;
529922a9f93SMark Brown goto err_free;
530922a9f93SMark Brown }
531922a9f93SMark Brown
532878ec67bSPhilipp Zabel if (clk_id == NULL)
53345f5ff81SStephen Warren return ctx;
534878ec67bSPhilipp Zabel
535878ec67bSPhilipp Zabel ctx->clk = clk_get(dev, clk_id);
536878ec67bSPhilipp Zabel if (IS_ERR(ctx->clk)) {
537878ec67bSPhilipp Zabel ret = PTR_ERR(ctx->clk);
538878ec67bSPhilipp Zabel goto err_free;
539878ec67bSPhilipp Zabel }
540878ec67bSPhilipp Zabel
541878ec67bSPhilipp Zabel ret = clk_prepare(ctx->clk);
542878ec67bSPhilipp Zabel if (ret < 0) {
543878ec67bSPhilipp Zabel clk_put(ctx->clk);
544878ec67bSPhilipp Zabel goto err_free;
545878ec67bSPhilipp Zabel }
546878ec67bSPhilipp Zabel
547878ec67bSPhilipp Zabel return ctx;
548878ec67bSPhilipp Zabel
549878ec67bSPhilipp Zabel err_free:
550878ec67bSPhilipp Zabel kfree(ctx);
551878ec67bSPhilipp Zabel
552878ec67bSPhilipp Zabel return ERR_PTR(ret);
55345f5ff81SStephen Warren }
55445f5ff81SStephen Warren
__regmap_init_mmio_clk(struct device * dev,const char * clk_id,void __iomem * regs,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)5553cfe7a74SNicolas Boichat struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
55645f5ff81SStephen Warren void __iomem *regs,
5573cfe7a74SNicolas Boichat const struct regmap_config *config,
5583cfe7a74SNicolas Boichat struct lock_class_key *lock_key,
5593cfe7a74SNicolas Boichat const char *lock_name)
56045f5ff81SStephen Warren {
56145f5ff81SStephen Warren struct regmap_mmio_context *ctx;
56245f5ff81SStephen Warren
563878ec67bSPhilipp Zabel ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
56445f5ff81SStephen Warren if (IS_ERR(ctx))
56545f5ff81SStephen Warren return ERR_CAST(ctx);
56645f5ff81SStephen Warren
5673cfe7a74SNicolas Boichat return __regmap_init(dev, ®map_mmio, ctx, config,
5683cfe7a74SNicolas Boichat lock_key, lock_name);
56945f5ff81SStephen Warren }
5703cfe7a74SNicolas Boichat EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);
57145f5ff81SStephen Warren
__devm_regmap_init_mmio_clk(struct device * dev,const char * clk_id,void __iomem * regs,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)5723cfe7a74SNicolas Boichat struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
5733cfe7a74SNicolas Boichat const char *clk_id,
57445f5ff81SStephen Warren void __iomem *regs,
5753cfe7a74SNicolas Boichat const struct regmap_config *config,
5763cfe7a74SNicolas Boichat struct lock_class_key *lock_key,
5773cfe7a74SNicolas Boichat const char *lock_name)
57845f5ff81SStephen Warren {
57945f5ff81SStephen Warren struct regmap_mmio_context *ctx;
58045f5ff81SStephen Warren
581878ec67bSPhilipp Zabel ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
58245f5ff81SStephen Warren if (IS_ERR(ctx))
58345f5ff81SStephen Warren return ERR_CAST(ctx);
58445f5ff81SStephen Warren
5853cfe7a74SNicolas Boichat return __devm_regmap_init(dev, ®map_mmio, ctx, config,
5863cfe7a74SNicolas Boichat lock_key, lock_name);
58745f5ff81SStephen Warren }
5883cfe7a74SNicolas Boichat EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);
58945f5ff81SStephen Warren
regmap_mmio_attach_clk(struct regmap * map,struct clk * clk)59031895662SMaxime Ripard int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk)
59131895662SMaxime Ripard {
59231895662SMaxime Ripard struct regmap_mmio_context *ctx = map->bus_context;
59331895662SMaxime Ripard
59431895662SMaxime Ripard ctx->clk = clk;
59531895662SMaxime Ripard ctx->attached_clk = true;
59631895662SMaxime Ripard
59731895662SMaxime Ripard return clk_prepare(ctx->clk);
59831895662SMaxime Ripard }
59931895662SMaxime Ripard EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk);
60031895662SMaxime Ripard
regmap_mmio_detach_clk(struct regmap * map)60131895662SMaxime Ripard void regmap_mmio_detach_clk(struct regmap *map)
60231895662SMaxime Ripard {
60331895662SMaxime Ripard struct regmap_mmio_context *ctx = map->bus_context;
60431895662SMaxime Ripard
60531895662SMaxime Ripard clk_unprepare(ctx->clk);
60631895662SMaxime Ripard
60731895662SMaxime Ripard ctx->attached_clk = false;
60831895662SMaxime Ripard ctx->clk = NULL;
60931895662SMaxime Ripard }
61031895662SMaxime Ripard EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk);
61131895662SMaxime Ripard
61245f5ff81SStephen Warren MODULE_LICENSE("GPL v2");
613