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 struct sandbox_emul_fake_regs r
[EMUL_GPIO_REG_END
]; /* Fake registers */
41 struct sandbox_spmi_priv
{
42 struct sandbox_emul_gpio gpios
[EMUL_GPIO_COUNT
];
45 /* Check if valid register was requested */
46 static bool check_address_valid(int usid
, int pid
, int off
)
50 if (pid
< EMUL_GPIO_PID_START
|| pid
> EMUL_GPIO_PID_END
)
52 if (off
> EMUL_GPIO_REG_END
)
57 static int sandbox_spmi_write(struct udevice
*dev
, int usid
, int pid
, int off
,
60 struct sandbox_spmi_priv
*priv
= dev_get_priv(dev
);
61 struct sandbox_emul_fake_regs
*regs
;
63 if (!check_address_valid(usid
, pid
, off
))
66 regs
= priv
->gpios
[pid
& 0x3].r
; /* Last 3 bits of pid are gpio # */
69 case 0x40: /* Control */
70 val
&= regs
[off
].access_mask
;
71 if (((val
& 0x30) == 0x10) || ((val
& 0x30) == 0x20)) {
72 /* out/inout - set status register */
73 regs
[0x8].value
&= ~0x1;
74 regs
[0x8].value
|= val
& 0x1;
78 if (regs
[off
].perms
& EMUL_PERM_W
)
79 regs
[off
].value
= val
& regs
[off
].access_mask
;
84 static int sandbox_spmi_read(struct udevice
*dev
, int usid
, int pid
, int off
)
86 struct sandbox_spmi_priv
*priv
= dev_get_priv(dev
);
87 struct sandbox_emul_fake_regs
*regs
;
89 if (!check_address_valid(usid
, pid
, off
))
92 regs
= priv
->gpios
[pid
& 0x3].r
; /* Last 3 bits of pid are gpio # */
94 if (regs
[0x46].value
== 0) /* Block disabled */
98 case 0x8: /* Status */
99 if (regs
[0x46].value
== 0) /* Block disabled */
101 return regs
[off
].value
;
103 if (regs
[off
].perms
& EMUL_PERM_R
)
104 return regs
[off
].value
;
110 static struct dm_spmi_ops sandbox_spmi_ops
= {
111 .read
= sandbox_spmi_read
,
112 .write
= sandbox_spmi_write
,
115 static int sandbox_spmi_probe(struct udevice
*dev
)
117 struct sandbox_spmi_priv
*priv
= dev_get_priv(dev
);
120 for (i
= 0; i
< EMUL_GPIO_COUNT
; ++i
) {
121 struct sandbox_emul_fake_regs
*regs
= priv
->gpios
[i
].r
;
122 regs
[4].perms
= EMUL_PERM_R
;
123 regs
[4].value
= 0x10;
124 regs
[5].perms
= EMUL_PERM_R
;
126 regs
[8].access_mask
= 0x81;
127 regs
[8].perms
= EMUL_PERM_RW
;
128 regs
[0x40].access_mask
= 0x7F;
129 regs
[0x40].perms
= EMUL_PERM_RW
;
130 regs
[0x41].access_mask
= 7;
131 regs
[0x41].perms
= EMUL_PERM_RW
;
132 regs
[0x42].access_mask
= 7;
133 regs
[0x42].perms
= EMUL_PERM_RW
;
134 regs
[0x42].value
= 0x4;
135 regs
[0x45].access_mask
= 0x3F;
136 regs
[0x45].perms
= EMUL_PERM_RW
;
137 regs
[0x45].value
= 0x1;
138 regs
[0x46].access_mask
= 0x80;
139 regs
[0x46].perms
= EMUL_PERM_RW
;
140 regs
[0x46].value
= 0x80;
145 static const struct udevice_id sandbox_spmi_ids
[] = {
146 { .compatible
= "sandbox,spmi" },
150 U_BOOT_DRIVER(msm_spmi
) = {
151 .name
= "sandbox_spmi",
153 .of_match
= sandbox_spmi_ids
,
154 .ops
= &sandbox_spmi_ops
,
155 .probe
= sandbox_spmi_probe
,
156 .priv_auto_alloc_size
= sizeof(struct sandbox_spmi_priv
),