xref: /openbsd/sys/arch/armv7/exynos/tps65090.c (revision 73471bf0)
1 /* $OpenBSD: tps65090.c,v 1.6 2021/10/24 17:52:27 mpi Exp $ */
2 /*
3  * Copyright (c) 2013 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/systm.h>
20 #include <sys/device.h>
21 
22 #include <dev/i2c/i2cvar.h>
23 
24 #define	REG_IRQ1		0x00
25 #define	REG_IRQ2		0x01
26 #define	REG_IRQ1MASK		0x02
27 #define	REG_IRQ2MASK		0x03
28 #define	REG_CG_CTRL0		0x04
29 #define	 REG_CG_CTRL0_ENC_MASK		(1 << 0)
30 #define	REG_CG_CTRL1		0x05
31 #define	REG_CG_CTRL2		0x06
32 #define	REG_CG_CTRL3		0x07
33 #define	REG_CG_CTRL4		0x08
34 #define	REG_CG_CTRL5		0x09
35 #define	REG_CG_STATUS1		0x0a
36 #define	REG_CG_STATUS2		0x0b
37 #define	REG_DCDC1_CTRL		0x0c
38 #define	REG_DCDC2_CTRL		0x0d
39 #define	REG_DCDC3_CTRL		0x0e
40 #define	REG_FET1_CTRL		0x0f
41 #define	REG_FET2_CTRL		0x10
42 #define	REG_FET3_CTRL		0x11
43 #define	REG_FET4_CTRL		0x12
44 #define	REG_FET5_CTRL		0x13
45 #define	REG_FET6_CTRL		0x14
46 #define	REG_FET7_CTRL		0x15
47 #define	REG_FETx_CTRL(x)	(0x0e + (x))
48 #define	 REG_FETx_CTRL_ENFET		(1 << 0) /* Enable FET */
49 #define	 REG_FETx_CTRL_ADENFET		(1 << 1) /* Enable output auto discharge */
50 #define	 REG_FETx_CTRL_WAIT		(3 << 2) /* Overcurrent timeout max */
51 #define	 REG_FETx_CTRL_PGFET		(1 << 4) /* Power good for FET status */
52 #define	 REG_FETx_CTRL_TOFET		(1 << 7) /* Timeout, startup, overload */
53 #define	REG_AD_CTRL		0x16
54 #define	REG_AD_OUT1		0x17
55 #define	REG_AD_OUT2		0x18
56 
57 #define	NFET			7
58 
59 #ifdef DEBUG
60 #define DPRINTF(x) printf x
61 #else
62 #define DPRINTF(x)
63 #endif
64 
65 struct tps65090_softc {
66 	struct device		sc_dev;
67 	i2c_tag_t sc_tag;
68 	i2c_addr_t sc_addr;
69 };
70 
71 struct tps65090_softc *tps65090_sc;
72 
73 int	tps65090_match(struct device *, void *, void *);
74 void	tps65090_attach(struct device *, struct device *, void *);
75 
76 int	tps65090_read_reg(struct tps65090_softc *, uint8_t);
77 void	tps65090_write_reg(struct tps65090_softc *, uint8_t, uint8_t);
78 int	tps65090_fet_set(int, int);
79 int	tps65090_fet_get(int);
80 void	tps65090_fet_enable(int);
81 void	tps65090_fet_disable(int);
82 int	tps65090_get_charging(void);
83 void	tps65090_set_charging(int);
84 
85 const struct cfattach tpspmic_ca = {
86 	sizeof(struct tps65090_softc), tps65090_match, tps65090_attach
87 };
88 
89 struct cfdriver tpspmic_cd = {
90 	NULL, "tpspmic", DV_DULL
91 };
92 
93 int
94 tps65090_match(struct device *parent, void *match, void *aux)
95 {
96 	struct i2c_attach_args *ia = aux;
97 
98 	if (strcmp(ia->ia_name, "ti,tps65090") == 0)
99 		return (1);
100 	return (0);
101 }
102 
103 void
104 tps65090_attach(struct device *parent, struct device *self, void *aux)
105 {
106 	struct tps65090_softc *sc = (struct tps65090_softc *)self;
107 	struct i2c_attach_args *ia = aux;
108 
109 	sc->sc_tag = ia->ia_tag;
110 	sc->sc_addr = ia->ia_addr;
111 	tps65090_sc = sc;
112 
113 	printf("\n");
114 }
115 
116 /*
117  * FET1: Backlight on the Chromebook
118  * FET6: LCD panel on the Chromebook
119  */
120 void
121 tps65090_fet_enable(int fet)
122 {
123 	int i;
124 
125 	if (fet < 1 || fet > NFET)
126 		return;
127 
128 	for (i = 0; i < 10; i++) {
129 		if (!tps65090_fet_set(fet, 1))
130 			break;
131 
132 		if (i != 9)
133 			tps65090_fet_set(fet, 0);
134 	}
135 }
136 
137 void
138 tps65090_fet_disable(int fet)
139 {
140 	if (fet < 1 || fet > NFET)
141 		return;
142 
143 	tps65090_fet_set(fet, 0);
144 }
145 
146 int
147 tps65090_fet_set(int fet, int set)
148 {
149 	struct tps65090_softc *sc = tps65090_sc;
150 	int i;
151 	uint8_t val, check;
152 
153 	val = REG_FETx_CTRL_ADENFET | REG_FETx_CTRL_WAIT;
154 	if (set)
155 		val |= REG_FETx_CTRL_ENFET;
156 
157 	tps65090_write_reg(sc, REG_FETx_CTRL(fet), val);
158 	for (i = 0; i < 5; i++) {
159 		check = tps65090_read_reg(sc, REG_FETx_CTRL(fet));
160 
161 		/* FET state correct? */
162 		if (!!(check & REG_FETx_CTRL_PGFET) == set)
163 			return 0;
164 
165 		/* Timeout, don't need to try again. */
166 		if (check & REG_FETx_CTRL_TOFET)
167 			break;
168 
169 		delay(1000);
170 	}
171 
172 	return -1;
173 }
174 
175 int
176 tps65090_fet_get(int fet)
177 {
178 	struct tps65090_softc *sc = tps65090_sc;
179 	uint8_t val = tps65090_read_reg(sc, REG_FETx_CTRL(fet));
180 	return val & REG_FETx_CTRL_ENFET;
181 }
182 
183 int
184 tps65090_get_charging(void)
185 {
186 	struct tps65090_softc *sc = tps65090_sc;
187 	uint8_t val = tps65090_read_reg(sc, REG_CG_CTRL0);
188 	return val & REG_CG_CTRL0_ENC_MASK;
189 }
190 
191 void
192 tps65090_set_charging(int set)
193 {
194 	struct tps65090_softc *sc = tps65090_sc;
195 	uint8_t val = tps65090_read_reg(sc, REG_CG_CTRL0);
196 	if (set)
197 		val |= REG_CG_CTRL0_ENC_MASK;
198 	else
199 		val &= REG_CG_CTRL0_ENC_MASK;
200 	tps65090_write_reg(sc, REG_CG_CTRL0, val);
201 }
202 
203 int
204 tps65090_read_reg(struct tps65090_softc *sc, uint8_t cmd)
205 {
206 	uint8_t val;
207 
208 	iic_acquire_bus(sc->sc_tag, 0);
209 	iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
210 	    sc->sc_addr, &cmd, 1, &val, 1, 0);
211 	iic_release_bus(sc->sc_tag, 0);
212 
213 	return val;
214 }
215 
216 void
217 tps65090_write_reg(struct tps65090_softc *sc, uint8_t cmd, uint8_t val)
218 {
219 	iic_acquire_bus(sc->sc_tag, 0);
220 	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
221 	    sc->sc_addr, &cmd, 1, &val, 1, 0);
222 	iic_release_bus(sc->sc_tag, 0);
223 }
224