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