xref: /openbsd-src/sys/dev/fdt/qcpmic.c (revision 27fef0cb61cabbc81023c540ad58aa8ad3e1e602)
1 /*	$OpenBSD: qcpmic.c,v 1.3 2025/01/03 14:13:55 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2022 Patrick Wildt <patrick@blueri.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/malloc.h>
20 #include <sys/systm.h>
21 #include <sys/timeout.h>
22 
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #include <dev/fdt/spmivar.h>
27 
28 #include <dev/ofw/openfirm.h>
29 #include <dev/ofw/fdt.h>
30 
31 /* PMIC Registers. */
32 #define PMIC_REV2	0x101
33 #define PMIC_REV3	0x102
34 #define PMIC_REV4	0x103
35 #define PMIC_TYPE	0x104
36 #define  PMIC_TYPE_VAL		0x51
37 #define PMIC_SUBTYPE	0x105
38 #define PMIC_FAB_ID	0x1f2
39 
40 struct qcpmic_softc {
41 	struct device		sc_dev;
42 	int			sc_node;
43 
44 	spmi_tag_t		sc_tag;
45 	int8_t			sc_sid;
46 
47 	void			*sc_ih;
48 
49 	struct timeout		sc_tick;
50 };
51 
52 int	qcpmic_match(struct device *, void *, void *);
53 void	qcpmic_attach(struct device *, struct device *, void *);
54 
55 const struct cfattach qcpmic_ca = {
56 	sizeof(struct qcpmic_softc), qcpmic_match, qcpmic_attach
57 };
58 
59 struct cfdriver qcpmic_cd = {
60 	NULL, "qcpmic", DV_DULL
61 };
62 
63 uint8_t	qcpmic_read(struct qcpmic_softc *, uint16_t);
64 
65 int
66 qcpmic_match(struct device *parent, void *match, void *aux)
67 {
68 	struct spmi_attach_args *saa = aux;
69 
70 	return OF_is_compatible(saa->sa_node, "qcom,spmi-pmic");
71 }
72 
73 void
74 qcpmic_attach(struct device *parent, struct device *self, void *aux)
75 {
76 	struct spmi_attach_args *saa = aux;
77 	struct qcpmic_softc *sc = (struct qcpmic_softc *)self;
78 	struct spmi_attach_args sa;
79 	char name[32];
80 	int node;
81 
82 	sc->sc_node = saa->sa_node;
83 	sc->sc_tag = saa->sa_tag;
84 	sc->sc_sid = saa->sa_sid;
85 
86 	if (qcpmic_read(sc, PMIC_TYPE) != PMIC_TYPE_VAL) {
87 		printf(": unknown PMIC type\n");
88 		return;
89 	}
90 
91 	printf("\n");
92 
93 	for (node = OF_child(saa->sa_node); node; node = OF_peer(node)) {
94 		memset(name, 0, sizeof(name));
95 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
96 			continue;
97 		if (name[0] == '\0')
98 			continue;
99 
100 		memset(&sa, 0, sizeof(sa));
101 		sa.sa_tag = sc->sc_tag;
102 		sa.sa_sid = sc->sc_sid;
103 		sa.sa_name = name;
104 		sa.sa_node = node;
105 		config_found(self, &sa, NULL);
106 	}
107 }
108 
109 uint8_t
110 qcpmic_read(struct qcpmic_softc *sc, uint16_t addr)
111 {
112 	uint8_t reg = 0;
113 	int err;
114 
115 	err = spmi_cmd_read(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_READL,
116 	    addr, &reg, sizeof(reg));
117 	if (err)
118 		printf("%s: error (%u) reading 0x%x", sc->sc_dev.dv_xname,
119 		    err, addr);
120 
121 	return reg;
122 }
123