2 * Sample SPMI bus driver
4 * It emulates bus with single pm8916-like pmic that has only GPIO reigsters.
6 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
8 * SPDX-License-Identifier: GPL-2.0+
14 #include <spmi/spmi.h>
18 DECLARE_GLOBAL_DATA_PTR
;
20 #define EMUL_GPIO_PID_START 0xC0
21 #define EMUL_GPIO_PID_END 0xC3
23 #define EMUL_GPIO_COUNT 4
25 #define EMUL_GPIO_REG_END 0x46 /* Last valid register */
27 #define EMUL_PERM_R 0x1
28 #define EMUL_PERM_W 0x2
29 #define EMUL_PERM_RW (EMUL_PERM_R | EMUL_PERM_W)
31 struct sandbox_emul_fake_regs
{
34 u8 perms
; /* Access permissions */
37 struct sandbox_emul_gpio
{
38 /* Fake registers - need one more entry as REG_END is valid address. */
39 struct sandbox_emul_fake_regs r
[EMUL_GPIO_REG_END
+ 1];
42 struct sandbox_spmi_priv
{
43 struct sandbox_emul_gpio gpios
[EMUL_GPIO_COUNT
];
46 /* Check if valid register was requested */
47 static bool check_address_valid(int usid
, int pid
, int off
)
51 if (pid
< EMUL_GPIO_PID_START
|| pid
> EMUL_GPIO_PID_END
)
53 if (off
> EMUL_GPIO_REG_END
)
58 static int sandbox_spmi_write(struct udevice
*dev
, int usid
, int pid
, int off
,
61 struct sandbox_spmi_priv
*priv
= dev_get_priv(dev
);
62 struct sandbox_emul_fake_regs
*regs
;
64 if (!check_address_valid(usid
, pid
, off
))
67 regs
= priv
->gpios
[pid
& 0x3].r
; /* Last 3 bits of pid are gpio # */
70 case 0x40: /* Control */
71 val
&= regs
[off
].access_mask
;
72 if (((val
& 0x30) == 0x10) || ((val
& 0x30) == 0x20)) {
73 /* out/inout - set status register */
74 regs
[0x8].value
&= ~0x1;
75 regs
[0x8].value
|= val
& 0x1;
79 if (regs
[off
].perms
& EMUL_PERM_W
)
80 regs
[off
].value
= val
& regs
[off
].access_mask
;
85 static int sandbox_spmi_read(struct udevice
*dev
, int usid
, int pid
, int off
)
87 struct sandbox_spmi_priv
*priv
= dev_get_priv(dev
);
88 struct sandbox_emul_fake_regs
*regs
;
90 if (!check_address_valid(usid
, pid
, off
))
93 regs
= priv
->gpios
[pid
& 0x3].r
; /* Last 3 bits of pid are gpio # */
95 if (regs
[0x46].value
== 0) /* Block disabled */
99 case 0x8: /* Status */
100 if (regs
[0x46].value
== 0) /* Block disabled */
102 return regs
[off
].value
;
104 if (regs
[off
].perms
& EMUL_PERM_R
)
105 return regs
[off
].value
;
111 static struct dm_spmi_ops sandbox_spmi_ops
= {
112 .read
= sandbox_spmi_read
,
113 .write
= sandbox_spmi_write
,
116 static int sandbox_spmi_probe(struct udevice
*dev
)
118 struct sandbox_spmi_priv
*priv
= dev_get_priv(dev
);
121 for (i
= 0; i
< EMUL_GPIO_COUNT
; ++i
) {
122 struct sandbox_emul_fake_regs
*regs
= priv
->gpios
[i
].r
;
123 regs
[4].perms
= EMUL_PERM_R
;
124 regs
[4].value
= 0x10;
125 regs
[5].perms
= EMUL_PERM_R
;
127 regs
[8].access_mask
= 0x81;
128 regs
[8].perms
= EMUL_PERM_RW
;
129 regs
[0x40].access_mask
= 0x7F;
130 regs
[0x40].perms
= EMUL_PERM_RW
;
131 regs
[0x41].access_mask
= 7;
132 regs
[0x41].perms
= EMUL_PERM_RW
;
133 regs
[0x42].access_mask
= 7;
134 regs
[0x42].perms
= EMUL_PERM_RW
;
135 regs
[0x42].value
= 0x4;
136 regs
[0x45].access_mask
= 0x3F;
137 regs
[0x45].perms
= EMUL_PERM_RW
;
138 regs
[0x45].value
= 0x1;
139 regs
[0x46].access_mask
= 0x80;
140 regs
[0x46].perms
= EMUL_PERM_RW
;
141 regs
[0x46].value
= 0x80;
146 static const struct udevice_id sandbox_spmi_ids
[] = {
147 { .compatible
= "sandbox,spmi" },
151 U_BOOT_DRIVER(msm_spmi
) = {
152 .name
= "sandbox_spmi",
154 .of_match
= sandbox_spmi_ids
,
155 .ops
= &sandbox_spmi_ops
,
156 .probe
= sandbox_spmi_probe
,
157 .priv_auto_alloc_size
= sizeof(struct sandbox_spmi_priv
),