2 * Qualcomm SPMI bus driver
4 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
6 * Loosely based on Little Kernel driver
8 * SPDX-License-Identifier: BSD-3-Clause
16 #include <spmi/spmi.h>
18 DECLARE_GLOBAL_DATA_PTR
;
20 /* PMIC Arbiter configuration registers */
21 #define PMIC_ARB_VERSION 0x0000
22 #define PMIC_ARB_VERSION_V2_MIN 0x20010000
24 #define ARB_CHANNEL_OFFSET(n) (0x4 * (n))
25 #define SPMI_CH_OFFSET(chnl) ((chnl) * 0x8000)
27 #define SPMI_REG_CMD0 0x0
28 #define SPMI_REG_CONFIG 0x4
29 #define SPMI_REG_STATUS 0x8
30 #define SPMI_REG_WDATA 0x10
31 #define SPMI_REG_RDATA 0x18
33 #define SPMI_CMD_OPCODE_SHIFT 27
34 #define SPMI_CMD_SLAVE_ID_SHIFT 20
35 #define SPMI_CMD_ADDR_SHIFT 12
36 #define SPMI_CMD_ADDR_OFFSET_SHIFT 4
37 #define SPMI_CMD_BYTE_CNT_SHIFT 0
39 #define SPMI_CMD_EXT_REG_WRITE_LONG 0x00
40 #define SPMI_CMD_EXT_REG_READ_LONG 0x01
42 #define SPMI_STATUS_DONE 0x1
44 #define SPMI_MAX_CHANNELS 128
45 #define SPMI_MAX_SLAVES 16
46 #define SPMI_MAX_PERIPH 256
48 struct msm_spmi_priv
{
49 phys_addr_t arb_chnl
; /* ARB channel mapping base */
50 phys_addr_t spmi_core
; /* SPMI core */
51 phys_addr_t spmi_obs
; /* SPMI observer */
52 /* SPMI channel map */
53 uint8_t channel_map
[SPMI_MAX_SLAVES
][SPMI_MAX_PERIPH
];
56 static int msm_spmi_write(struct udevice
*dev
, int usid
, int pid
, int off
,
59 struct msm_spmi_priv
*priv
= dev_get_priv(dev
);
63 if (usid
>= SPMI_MAX_SLAVES
)
65 if (pid
>= SPMI_MAX_PERIPH
)
68 channel
= priv
->channel_map
[usid
][pid
];
70 /* Disable IRQ mode for the current channel*/
71 writel(0x0, priv
->spmi_core
+ SPMI_CH_OFFSET(channel
) +
74 /* Write single byte */
75 writel(val
, priv
->spmi_core
+ SPMI_CH_OFFSET(channel
) + SPMI_REG_WDATA
);
77 /* Prepare write command */
78 reg
|= SPMI_CMD_EXT_REG_WRITE_LONG
<< SPMI_CMD_OPCODE_SHIFT
;
79 reg
|= (usid
<< SPMI_CMD_SLAVE_ID_SHIFT
);
80 reg
|= (pid
<< SPMI_CMD_ADDR_SHIFT
);
81 reg
|= (off
<< SPMI_CMD_ADDR_OFFSET_SHIFT
);
82 reg
|= 1; /* byte count */
84 /* Send write command */
85 writel(reg
, priv
->spmi_core
+ SPMI_CH_OFFSET(channel
) + SPMI_REG_CMD0
);
87 /* Wait till CMD DONE status */
90 reg
= readl(priv
->spmi_core
+ SPMI_CH_OFFSET(channel
) +
94 if (reg
^ SPMI_STATUS_DONE
) {
95 printf("SPMI write failure.\n");
102 static int msm_spmi_read(struct udevice
*dev
, int usid
, int pid
, int off
)
104 struct msm_spmi_priv
*priv
= dev_get_priv(dev
);
108 if (usid
>= SPMI_MAX_SLAVES
)
110 if (pid
>= SPMI_MAX_PERIPH
)
113 channel
= priv
->channel_map
[usid
][pid
];
115 /* Disable IRQ mode for the current channel*/
116 writel(0x0, priv
->spmi_obs
+ SPMI_CH_OFFSET(channel
) + SPMI_REG_CONFIG
);
118 /* Prepare read command */
119 reg
|= SPMI_CMD_EXT_REG_READ_LONG
<< SPMI_CMD_OPCODE_SHIFT
;
120 reg
|= (usid
<< SPMI_CMD_SLAVE_ID_SHIFT
);
121 reg
|= (pid
<< SPMI_CMD_ADDR_SHIFT
);
122 reg
|= (off
<< SPMI_CMD_ADDR_OFFSET_SHIFT
);
123 reg
|= 1; /* byte count */
126 writel(reg
, priv
->spmi_obs
+ SPMI_CH_OFFSET(channel
) + SPMI_REG_CMD0
);
128 /* Wait till CMD DONE status */
131 reg
= readl(priv
->spmi_obs
+ SPMI_CH_OFFSET(channel
) +
135 if (reg
^ SPMI_STATUS_DONE
) {
136 printf("SPMI read failure.\n");
141 return readl(priv
->spmi_obs
+ SPMI_CH_OFFSET(channel
) +
142 SPMI_REG_RDATA
) & 0xFF;
145 static struct dm_spmi_ops msm_spmi_ops
= {
146 .read
= msm_spmi_read
,
147 .write
= msm_spmi_write
,
150 static int msm_spmi_probe(struct udevice
*dev
)
152 struct udevice
*parent
= dev
->parent
;
153 struct msm_spmi_priv
*priv
= dev_get_priv(dev
);
154 int node
= dev_of_offset(dev
);
159 priv
->arb_chnl
= devfdt_get_addr(dev
);
160 priv
->spmi_core
= fdtdec_get_addr_size_auto_parent(gd
->fdt_blob
,
161 dev_of_offset(parent
), node
, "reg", 1, NULL
, false);
162 priv
->spmi_obs
= fdtdec_get_addr_size_auto_parent(gd
->fdt_blob
,
163 dev_of_offset(parent
), node
, "reg", 2, NULL
, false);
165 hw_ver
= readl(priv
->arb_chnl
+ PMIC_ARB_VERSION
- 0x800);
166 is_v1
= (hw_ver
< PMIC_ARB_VERSION_V2_MIN
);
168 dev_dbg(dev
, "PMIC Arb Version-%d (0x%x)\n", (is_v1
? 1 : 2), hw_ver
);
170 if (priv
->arb_chnl
== FDT_ADDR_T_NONE
||
171 priv
->spmi_core
== FDT_ADDR_T_NONE
||
172 priv
->spmi_obs
== FDT_ADDR_T_NONE
)
175 /* Scan peripherals connected to each SPMI channel */
176 for (i
= 0; i
< SPMI_MAX_PERIPH
; i
++) {
177 uint32_t periph
= readl(priv
->arb_chnl
+ ARB_CHANNEL_OFFSET(i
));
178 uint8_t slave_id
= (periph
& 0xf0000) >> 16;
179 uint8_t pid
= (periph
& 0xff00) >> 8;
181 priv
->channel_map
[slave_id
][pid
] = i
;
186 static const struct udevice_id msm_spmi_ids
[] = {
187 { .compatible
= "qcom,spmi-pmic-arb" },
191 U_BOOT_DRIVER(msm_spmi
) = {
194 .of_match
= msm_spmi_ids
,
195 .ops
= &msm_spmi_ops
,
196 .probe
= msm_spmi_probe
,
197 .priv_auto_alloc_size
= sizeof(struct msm_spmi_priv
),