xref: /openbsd/sys/dev/fdt/qcpmic.c (revision 4bdff4be)
1 /*	$OpenBSD: qcpmic.c,v 1.1 2022/11/08 19:40:08 patrick 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/ofw_clock.h>
30 #include <dev/ofw/ofw_power.h>
31 #include <dev/ofw/fdt.h>
32 
33 /* PMIC Registers. */
34 #define PMIC_REV2	0x101
35 #define PMIC_REV3	0x102
36 #define PMIC_REV4	0x103
37 #define PMIC_TYPE	0x104
38 #define  PMIC_TYPE_VAL		0x51
39 #define PMIC_SUBTYPE	0x105
40 #define PMIC_FAB_ID	0x1f2
41 
42 struct qcpmic_softc {
43 	struct device		sc_dev;
44 	int			sc_node;
45 
46 	spmi_tag_t		sc_tag;
47 	int8_t			sc_sid;
48 
49 	void			*sc_ih;
50 
51 	struct timeout		sc_tick;
52 };
53 
54 int	qcpmic_match(struct device *, void *, void *);
55 void	qcpmic_attach(struct device *, struct device *, void *);
56 
57 const struct cfattach qcpmic_ca = {
58 	sizeof(struct qcpmic_softc), qcpmic_match, qcpmic_attach
59 };
60 
61 struct cfdriver qcpmic_cd = {
62 	NULL, "qcpmic", DV_DULL
63 };
64 
65 uint8_t	qcpmic_read(struct qcpmic_softc *, uint16_t);
66 
67 int
68 qcpmic_match(struct device *parent, void *match, void *aux)
69 {
70 	struct spmi_attach_args *saa = aux;
71 
72 	return OF_is_compatible(saa->sa_node, "qcom,spmi-pmic");
73 }
74 
75 void
76 qcpmic_attach(struct device *parent, struct device *self, void *aux)
77 {
78 	struct spmi_attach_args *saa = aux;
79 	struct qcpmic_softc *sc = (struct qcpmic_softc *)self;
80 	struct spmi_attach_args sa;
81 	char name[32];
82 	int node;
83 
84 	sc->sc_node = saa->sa_node;
85 	sc->sc_tag = saa->sa_tag;
86 	sc->sc_sid = saa->sa_sid;
87 
88 	if (qcpmic_read(sc, PMIC_TYPE) != PMIC_TYPE_VAL) {
89 		printf(": unknown PMIC type\n");
90 		return;
91 	}
92 
93 	printf("\n");
94 
95 	for (node = OF_child(saa->sa_node); node; node = OF_peer(node)) {
96 		memset(name, 0, sizeof(name));
97 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
98 			continue;
99 		if (name[0] == '\0')
100 			continue;
101 
102 		memset(&sa, 0, sizeof(sa));
103 		sa.sa_tag = sc->sc_tag;
104 		sa.sa_sid = sc->sc_sid;
105 		sa.sa_name = name;
106 		sa.sa_node = node;
107 		config_found(self, &sa, NULL);
108 	}
109 }
110 
111 uint8_t
112 qcpmic_read(struct qcpmic_softc *sc, uint16_t addr)
113 {
114 	uint8_t reg = 0;
115 	int err;
116 
117 	err = spmi_cmd_read(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_READL,
118 	    addr, &reg, sizeof(reg));
119 	if (err)
120 		printf("%s: error (%u) reading 0x%x\n", sc->sc_dev.dv_xname,
121 		    err, addr);
122 
123 	return reg;
124 }
125