xref: /dflybsd-src/sys/dev/drm/i915/intel_i2c.c (revision 9edbd4a07c3138f5c4f076f77de5d722fcc606cc)
1bad0eccaSFrançois Tigeot /*
2bad0eccaSFrançois Tigeot  * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
3bad0eccaSFrançois Tigeot  * Copyright © 2006-2008,2010 Intel Corporation
4bad0eccaSFrançois Tigeot  *   Jesse Barnes <jesse.barnes@intel.com>
5bad0eccaSFrançois Tigeot  *
6bad0eccaSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
7bad0eccaSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
8bad0eccaSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
9bad0eccaSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10bad0eccaSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
11bad0eccaSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
12bad0eccaSFrançois Tigeot  *
13bad0eccaSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
14bad0eccaSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
15bad0eccaSFrançois Tigeot  * Software.
16bad0eccaSFrançois Tigeot  *
17bad0eccaSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18bad0eccaSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19bad0eccaSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20bad0eccaSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21bad0eccaSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22bad0eccaSFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23bad0eccaSFrançois Tigeot  * DEALINGS IN THE SOFTWARE.
24bad0eccaSFrançois Tigeot  *
25bad0eccaSFrançois Tigeot  * Authors:
26bad0eccaSFrançois Tigeot  *	Eric Anholt <eric@anholt.net>
27bad0eccaSFrançois Tigeot  *	Chris Wilson <chris@chris-wilson.co.uk>
28bad0eccaSFrançois Tigeot  *
29bad0eccaSFrançois Tigeot  * Copyright (c) 2011 The FreeBSD Foundation
30bad0eccaSFrançois Tigeot  * All rights reserved.
31bad0eccaSFrançois Tigeot  *
32bad0eccaSFrançois Tigeot  * This software was developed by Konstantin Belousov under sponsorship from
33bad0eccaSFrançois Tigeot  * the FreeBSD Foundation.
34bad0eccaSFrançois Tigeot  *
35bad0eccaSFrançois Tigeot  * Redistribution and use in source and binary forms, with or without
36bad0eccaSFrançois Tigeot  * modification, are permitted provided that the following conditions
37bad0eccaSFrançois Tigeot  * are met:
38bad0eccaSFrançois Tigeot  * 1. Redistributions of source code must retain the above copyright
39bad0eccaSFrançois Tigeot  *    notice, this list of conditions and the following disclaimer.
40bad0eccaSFrançois Tigeot  * 2. Redistributions in binary form must reproduce the above copyright
41bad0eccaSFrançois Tigeot  *    notice, this list of conditions and the following disclaimer in the
42bad0eccaSFrançois Tigeot  *    documentation and/or other materials provided with the distribution.
43bad0eccaSFrançois Tigeot  *
44bad0eccaSFrançois Tigeot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45bad0eccaSFrançois Tigeot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46bad0eccaSFrançois Tigeot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47bad0eccaSFrançois Tigeot  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48bad0eccaSFrançois Tigeot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49bad0eccaSFrançois Tigeot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50bad0eccaSFrançois Tigeot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51bad0eccaSFrançois Tigeot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52bad0eccaSFrançois Tigeot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53bad0eccaSFrançois Tigeot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54bad0eccaSFrançois Tigeot  * SUCH DAMAGE.
55bad0eccaSFrançois Tigeot  */
56bad0eccaSFrançois Tigeot 
57bad0eccaSFrançois Tigeot #include <sys/mplock2.h>
58bad0eccaSFrançois Tigeot 
59a2fdbec6SFrançois Tigeot #include <linux/i2c.h>
60a2fdbec6SFrançois Tigeot #include <linux/export.h>
61bad0eccaSFrançois Tigeot #include <drm/drmP.h>
62a2fdbec6SFrançois Tigeot #include "intel_drv.h"
63bad0eccaSFrançois Tigeot #include <drm/i915_drm.h>
64bad0eccaSFrançois Tigeot #include "i915_drv.h"
65a2fdbec6SFrançois Tigeot 
66bad0eccaSFrançois Tigeot #include <bus/iicbus/iic.h>
67bad0eccaSFrançois Tigeot #include <bus/iicbus/iiconf.h>
68bad0eccaSFrançois Tigeot #include <bus/iicbus/iicbus.h>
69bad0eccaSFrançois Tigeot #include "iicbus_if.h"
70bad0eccaSFrançois Tigeot #include "iicbb_if.h"
71bad0eccaSFrançois Tigeot 
72*9edbd4a0SFrançois Tigeot enum disp_clk {
73*9edbd4a0SFrançois Tigeot 	CDCLK,
74*9edbd4a0SFrançois Tigeot 	CZCLK
75*9edbd4a0SFrançois Tigeot };
76*9edbd4a0SFrançois Tigeot 
77a2fdbec6SFrançois Tigeot struct gmbus_port {
78a2fdbec6SFrançois Tigeot 	const char *name;
79a2fdbec6SFrançois Tigeot 	int reg;
80a2fdbec6SFrançois Tigeot };
81a2fdbec6SFrançois Tigeot 
82a2fdbec6SFrançois Tigeot static const struct gmbus_port gmbus_ports[] = {
83a2fdbec6SFrançois Tigeot 	{ "ssc", GPIOB },
84a2fdbec6SFrançois Tigeot 	{ "vga", GPIOA },
85a2fdbec6SFrançois Tigeot 	{ "panel", GPIOC },
86a2fdbec6SFrançois Tigeot 	{ "dpc", GPIOD },
87a2fdbec6SFrançois Tigeot 	{ "dpb", GPIOE },
88a2fdbec6SFrançois Tigeot 	{ "dpd", GPIOF },
89a2fdbec6SFrançois Tigeot };
90bad0eccaSFrançois Tigeot 
91bad0eccaSFrançois Tigeot /* Intel GPIO access functions */
92bad0eccaSFrançois Tigeot 
93bad0eccaSFrançois Tigeot #define I2C_RISEFALL_TIME 10
94bad0eccaSFrançois Tigeot 
95*9edbd4a0SFrançois Tigeot static int get_disp_clk_div(struct drm_i915_private *dev_priv,
96*9edbd4a0SFrançois Tigeot 			    enum disp_clk clk)
97*9edbd4a0SFrançois Tigeot {
98*9edbd4a0SFrançois Tigeot 	u32 reg_val;
99*9edbd4a0SFrançois Tigeot 	int clk_ratio;
100*9edbd4a0SFrançois Tigeot 
101*9edbd4a0SFrançois Tigeot 	reg_val = I915_READ(CZCLK_CDCLK_FREQ_RATIO);
102*9edbd4a0SFrançois Tigeot 
103*9edbd4a0SFrançois Tigeot 	if (clk == CDCLK)
104*9edbd4a0SFrançois Tigeot 		clk_ratio =
105*9edbd4a0SFrançois Tigeot 			((reg_val & CDCLK_FREQ_MASK) >> CDCLK_FREQ_SHIFT) + 1;
106*9edbd4a0SFrançois Tigeot 	else
107*9edbd4a0SFrançois Tigeot 		clk_ratio = (reg_val & CZCLK_FREQ_MASK) + 1;
108*9edbd4a0SFrançois Tigeot 
109*9edbd4a0SFrançois Tigeot 	return clk_ratio;
110*9edbd4a0SFrançois Tigeot }
111*9edbd4a0SFrançois Tigeot 
112*9edbd4a0SFrançois Tigeot static void gmbus_set_freq(struct drm_i915_private *dev_priv)
113*9edbd4a0SFrançois Tigeot {
114*9edbd4a0SFrançois Tigeot 	int vco, gmbus_freq = 0, cdclk_div;
115*9edbd4a0SFrançois Tigeot 
116*9edbd4a0SFrançois Tigeot 	BUG_ON(!IS_VALLEYVIEW(dev_priv->dev));
117*9edbd4a0SFrançois Tigeot 
118*9edbd4a0SFrançois Tigeot 	vco = valleyview_get_vco(dev_priv);
119*9edbd4a0SFrançois Tigeot 
120*9edbd4a0SFrançois Tigeot 	/* Get the CDCLK divide ratio */
121*9edbd4a0SFrançois Tigeot 	cdclk_div = get_disp_clk_div(dev_priv, CDCLK);
122*9edbd4a0SFrançois Tigeot 
123*9edbd4a0SFrançois Tigeot 	/*
124*9edbd4a0SFrançois Tigeot 	 * Program the gmbus_freq based on the cdclk frequency.
125*9edbd4a0SFrançois Tigeot 	 * BSpec erroneously claims we should aim for 4MHz, but
126*9edbd4a0SFrançois Tigeot 	 * in fact 1MHz is the correct frequency.
127*9edbd4a0SFrançois Tigeot 	 */
128*9edbd4a0SFrançois Tigeot 	if (cdclk_div)
129*9edbd4a0SFrançois Tigeot 		gmbus_freq = (vco << 1) / cdclk_div;
130*9edbd4a0SFrançois Tigeot 
131*9edbd4a0SFrançois Tigeot 	if (WARN_ON(gmbus_freq == 0))
132*9edbd4a0SFrançois Tigeot 		return;
133*9edbd4a0SFrançois Tigeot 
134*9edbd4a0SFrançois Tigeot 	I915_WRITE(GMBUSFREQ_VLV, gmbus_freq);
135*9edbd4a0SFrançois Tigeot }
136*9edbd4a0SFrançois Tigeot 
137a2fdbec6SFrançois Tigeot void
138a2fdbec6SFrançois Tigeot intel_i2c_reset(struct drm_device *dev)
139a2fdbec6SFrançois Tigeot {
140a2fdbec6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
141*9edbd4a0SFrançois Tigeot 
142*9edbd4a0SFrançois Tigeot 	/*
143*9edbd4a0SFrançois Tigeot 	 * In BIOS-less system, program the correct gmbus frequency
144*9edbd4a0SFrançois Tigeot 	 * before reading edid.
145*9edbd4a0SFrançois Tigeot 	 */
146*9edbd4a0SFrançois Tigeot 	if (IS_VALLEYVIEW(dev))
147*9edbd4a0SFrançois Tigeot 		gmbus_set_freq(dev_priv);
148*9edbd4a0SFrançois Tigeot 
149a2fdbec6SFrançois Tigeot 	I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0);
150a2fdbec6SFrançois Tigeot 	I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0);
151a2fdbec6SFrançois Tigeot }
152a2fdbec6SFrançois Tigeot 
153a2fdbec6SFrançois Tigeot static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
154bad0eccaSFrançois Tigeot {
155bad0eccaSFrançois Tigeot 	u32 val;
156bad0eccaSFrançois Tigeot 
157bad0eccaSFrançois Tigeot 	/* When using bit bashing for I2C, this bit needs to be set to 1 */
158bad0eccaSFrançois Tigeot 	if (!IS_PINEVIEW(dev_priv->dev))
159bad0eccaSFrançois Tigeot 		return;
160bad0eccaSFrançois Tigeot 
161bad0eccaSFrançois Tigeot 	val = I915_READ(DSPCLK_GATE_D);
162bad0eccaSFrançois Tigeot 	if (enable)
163bad0eccaSFrançois Tigeot 		val |= DPCUNIT_CLOCK_GATE_DISABLE;
164bad0eccaSFrançois Tigeot 	else
165bad0eccaSFrançois Tigeot 		val &= ~DPCUNIT_CLOCK_GATE_DISABLE;
166bad0eccaSFrançois Tigeot 	I915_WRITE(DSPCLK_GATE_D, val);
167bad0eccaSFrançois Tigeot }
168bad0eccaSFrançois Tigeot 
169a2fdbec6SFrançois Tigeot static u32 get_reserved(device_t idev)
170a2fdbec6SFrançois Tigeot {
171a2fdbec6SFrançois Tigeot 	struct intel_iic_softc *sc = device_get_softc(idev);
172a2fdbec6SFrançois Tigeot 	struct drm_device *dev = sc->drm_dev;
173a2fdbec6SFrançois Tigeot 	struct drm_i915_private *dev_priv;
174a2fdbec6SFrançois Tigeot 	u32 reserved = 0;
175a2fdbec6SFrançois Tigeot 
176a2fdbec6SFrançois Tigeot 	dev_priv = dev->dev_private;
177a2fdbec6SFrançois Tigeot 
178a2fdbec6SFrançois Tigeot 	/* On most chips, these bits must be preserved in software. */
179a2fdbec6SFrançois Tigeot 	if (!IS_I830(dev) && !IS_845G(dev))
180a2fdbec6SFrançois Tigeot 		reserved = I915_READ_NOTRACE(sc->reg) &
181a2fdbec6SFrançois Tigeot 					     (GPIO_DATA_PULLUP_DISABLE |
182a2fdbec6SFrançois Tigeot 					      GPIO_CLOCK_PULLUP_DISABLE);
183a2fdbec6SFrançois Tigeot 
184a2fdbec6SFrançois Tigeot 	return reserved;
185a2fdbec6SFrançois Tigeot }
186a2fdbec6SFrançois Tigeot 
187a2fdbec6SFrançois Tigeot static int get_clock(device_t idev)
188bad0eccaSFrançois Tigeot {
189bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
190bad0eccaSFrançois Tigeot 	struct drm_i915_private *dev_priv;
191bad0eccaSFrançois Tigeot 	u32 reserved;
192bad0eccaSFrançois Tigeot 
193bad0eccaSFrançois Tigeot 	sc = device_get_softc(idev);
194a2fdbec6SFrançois Tigeot 	dev_priv = sc->drm_dev->dev_private;
195bad0eccaSFrançois Tigeot 
196a2fdbec6SFrançois Tigeot 	reserved = get_reserved(idev);
197a2fdbec6SFrançois Tigeot 
198a2fdbec6SFrançois Tigeot 	I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_CLOCK_DIR_MASK);
199a2fdbec6SFrançois Tigeot 	I915_WRITE_NOTRACE(sc->reg, reserved);
200a2fdbec6SFrançois Tigeot 	return ((I915_READ_NOTRACE(sc->reg) & GPIO_CLOCK_VAL_IN) != 0);
201bad0eccaSFrançois Tigeot }
202bad0eccaSFrançois Tigeot 
203a2fdbec6SFrançois Tigeot static int get_data(device_t idev)
204bad0eccaSFrançois Tigeot {
205a2fdbec6SFrançois Tigeot 	struct intel_iic_softc *sc;
206bad0eccaSFrançois Tigeot 	struct drm_i915_private *dev_priv;
207a2fdbec6SFrançois Tigeot 	u32 reserved;
208bad0eccaSFrançois Tigeot 
209a2fdbec6SFrançois Tigeot 	sc = device_get_softc(idev);
210a2fdbec6SFrançois Tigeot 	dev_priv = sc->drm_dev->dev_private;
211a2fdbec6SFrançois Tigeot 
212a2fdbec6SFrançois Tigeot 	reserved = get_reserved(idev);
213a2fdbec6SFrançois Tigeot 
214a2fdbec6SFrançois Tigeot 	I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_DATA_DIR_MASK);
215a2fdbec6SFrançois Tigeot 	I915_WRITE_NOTRACE(sc->reg, reserved);
216a2fdbec6SFrançois Tigeot 	return ((I915_READ_NOTRACE(sc->reg) & GPIO_DATA_VAL_IN) != 0);
217bad0eccaSFrançois Tigeot }
218bad0eccaSFrançois Tigeot 
219bad0eccaSFrançois Tigeot static int
220bad0eccaSFrançois Tigeot intel_iicbus_reset(device_t idev, u_char speed, u_char addr, u_char *oldaddr)
221bad0eccaSFrançois Tigeot {
222bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
223bad0eccaSFrançois Tigeot 	struct drm_device *dev;
224bad0eccaSFrançois Tigeot 
225bad0eccaSFrançois Tigeot 	sc = device_get_softc(idev);
226bad0eccaSFrançois Tigeot 	dev = sc->drm_dev;
227bad0eccaSFrançois Tigeot 
2283f2f609dSFrançois Tigeot 	intel_i2c_reset(dev);
229bad0eccaSFrançois Tigeot 	return (0);
230bad0eccaSFrançois Tigeot }
231bad0eccaSFrançois Tigeot 
232a2fdbec6SFrançois Tigeot static void set_clock(device_t idev, int val)
233bad0eccaSFrançois Tigeot {
234bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
235bad0eccaSFrançois Tigeot 	struct drm_i915_private *dev_priv;
236bad0eccaSFrançois Tigeot 	u32 clock_bits, reserved;
237bad0eccaSFrançois Tigeot 
238bad0eccaSFrançois Tigeot 	sc = device_get_softc(idev);
239bad0eccaSFrançois Tigeot 	dev_priv = sc->drm_dev->dev_private;
240bad0eccaSFrançois Tigeot 
241a2fdbec6SFrançois Tigeot 	reserved = get_reserved(idev);
242bad0eccaSFrançois Tigeot 	if (val)
243bad0eccaSFrançois Tigeot 		clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
244bad0eccaSFrançois Tigeot 	else
245bad0eccaSFrançois Tigeot 		clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
246bad0eccaSFrançois Tigeot 		    GPIO_CLOCK_VAL_MASK;
247bad0eccaSFrançois Tigeot 
248bad0eccaSFrançois Tigeot 	I915_WRITE_NOTRACE(sc->reg, reserved | clock_bits);
249bad0eccaSFrançois Tigeot 	POSTING_READ(sc->reg);
250bad0eccaSFrançois Tigeot }
251bad0eccaSFrançois Tigeot 
252a2fdbec6SFrançois Tigeot static void set_data(device_t idev, int val)
253bad0eccaSFrançois Tigeot {
254bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
255bad0eccaSFrançois Tigeot 	struct drm_i915_private *dev_priv;
256bad0eccaSFrançois Tigeot 	u32 reserved;
257a2fdbec6SFrançois Tigeot 	u32 data_bits;
258bad0eccaSFrançois Tigeot 
259bad0eccaSFrançois Tigeot 	sc = device_get_softc(idev);
260bad0eccaSFrançois Tigeot 	dev_priv = sc->drm_dev->dev_private;
261bad0eccaSFrançois Tigeot 
262a2fdbec6SFrançois Tigeot 	reserved = get_reserved(idev);
263a2fdbec6SFrançois Tigeot 	if (val)
264a2fdbec6SFrançois Tigeot 		data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
265a2fdbec6SFrançois Tigeot 	else
266a2fdbec6SFrançois Tigeot 		data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
267a2fdbec6SFrançois Tigeot 		    GPIO_DATA_VAL_MASK;
268bad0eccaSFrançois Tigeot 
269a2fdbec6SFrançois Tigeot 	I915_WRITE_NOTRACE(sc->reg, reserved | data_bits);
270a2fdbec6SFrançois Tigeot 	POSTING_READ(sc->reg);
271bad0eccaSFrançois Tigeot }
272bad0eccaSFrançois Tigeot 
273a2fdbec6SFrançois Tigeot static const char *gpio_names[GMBUS_NUM_PORTS] = {
274a2fdbec6SFrançois Tigeot 	"ssc",
275a2fdbec6SFrançois Tigeot 	"vga",
276a2fdbec6SFrançois Tigeot 	"panel",
277a2fdbec6SFrançois Tigeot 	"dpc",
278a2fdbec6SFrançois Tigeot 	"dpb",
279a2fdbec6SFrançois Tigeot 	"dpd",
280a2fdbec6SFrançois Tigeot };
281a2fdbec6SFrançois Tigeot 
282bad0eccaSFrançois Tigeot static int
283a2fdbec6SFrançois Tigeot intel_gpio_setup(device_t idev)
284bad0eccaSFrançois Tigeot {
285a2fdbec6SFrançois Tigeot 	static const int map_pin_to_reg[] = {
286a2fdbec6SFrançois Tigeot 		0,
287a2fdbec6SFrançois Tigeot 		GPIOB,
288a2fdbec6SFrançois Tigeot 		GPIOA,
289a2fdbec6SFrançois Tigeot 		GPIOC,
290a2fdbec6SFrançois Tigeot 		GPIOD,
291a2fdbec6SFrançois Tigeot 		GPIOE,
292a2fdbec6SFrançois Tigeot 		GPIOF,
293a2fdbec6SFrançois Tigeot 		0
294a2fdbec6SFrançois Tigeot 	};
295a2fdbec6SFrançois Tigeot 
296bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
297bad0eccaSFrançois Tigeot 	struct drm_i915_private *dev_priv;
298a2fdbec6SFrançois Tigeot 	int pin;
299bad0eccaSFrançois Tigeot 
300bad0eccaSFrançois Tigeot 	sc = device_get_softc(idev);
301a2fdbec6SFrançois Tigeot 	sc->drm_dev = device_get_softc(device_get_parent(idev));
302bad0eccaSFrançois Tigeot 	dev_priv = sc->drm_dev->dev_private;
303a2fdbec6SFrançois Tigeot 	pin = device_get_unit(idev);
304bad0eccaSFrançois Tigeot 
305a2fdbec6SFrançois Tigeot 	ksnprintf(sc->name, sizeof(sc->name), "i915 iicbb %s", gpio_names[pin]);
306a2fdbec6SFrançois Tigeot 	device_set_desc(idev, sc->name);
307bad0eccaSFrançois Tigeot 
308a2fdbec6SFrançois Tigeot 	sc->reg0 = (pin + 1) | GMBUS_RATE_100KHZ;
309a2fdbec6SFrançois Tigeot 	sc->reg = map_pin_to_reg[pin + 1];
310a2fdbec6SFrançois Tigeot 	if (HAS_PCH_SPLIT(dev_priv->dev))
311a2fdbec6SFrançois Tigeot 		sc->reg += PCH_GPIOA - GPIOA;
312a2fdbec6SFrançois Tigeot 
313a2fdbec6SFrançois Tigeot 	/* add generic bit-banging code */
314a2fdbec6SFrançois Tigeot 	sc->iic_dev = device_add_child(idev, "iicbb", -1);
315a2fdbec6SFrançois Tigeot 	if (sc->iic_dev == NULL)
316a2fdbec6SFrançois Tigeot 		return (ENXIO);
317a2fdbec6SFrançois Tigeot 	device_quiet(sc->iic_dev);
318a2fdbec6SFrançois Tigeot 	bus_generic_attach(idev);
319a2fdbec6SFrançois Tigeot 
320a2fdbec6SFrançois Tigeot 	return (0);
321bad0eccaSFrançois Tigeot }
322bad0eccaSFrançois Tigeot 
323bad0eccaSFrançois Tigeot static int
324a2fdbec6SFrançois Tigeot intel_i2c_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs)
325bad0eccaSFrançois Tigeot {
326a2fdbec6SFrançois Tigeot 	device_t bridge_dev;
327bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
328bad0eccaSFrançois Tigeot 	struct drm_i915_private *dev_priv;
329a2fdbec6SFrançois Tigeot 	int ret;
330a2fdbec6SFrançois Tigeot 	int i;
331a2fdbec6SFrançois Tigeot 
332a2fdbec6SFrançois Tigeot 	bridge_dev = device_get_parent(device_get_parent(idev));
333a2fdbec6SFrançois Tigeot 	sc = device_get_softc(bridge_dev);
334a2fdbec6SFrançois Tigeot 	dev_priv = sc->drm_dev->dev_private;
335a2fdbec6SFrançois Tigeot 
336a2fdbec6SFrançois Tigeot 	intel_i2c_reset(sc->drm_dev);
337a2fdbec6SFrançois Tigeot 	intel_i2c_quirk_set(dev_priv, true);
338a2fdbec6SFrançois Tigeot 	IICBB_SETSDA(bridge_dev, 1);
339a2fdbec6SFrançois Tigeot 	IICBB_SETSCL(bridge_dev, 1);
340a2fdbec6SFrançois Tigeot 	DELAY(I2C_RISEFALL_TIME);
341a2fdbec6SFrançois Tigeot 
342a2fdbec6SFrançois Tigeot 	for (i = 0; i < nmsgs - 1; i++) {
343a2fdbec6SFrançois Tigeot 		/* force use of repeated start instead of default stop+start */
344a2fdbec6SFrançois Tigeot 		msgs[i].flags |= IIC_M_NOSTOP;
345a2fdbec6SFrançois Tigeot 	}
346a2fdbec6SFrançois Tigeot 	ret = iicbus_transfer(idev, msgs, nmsgs);
347a2fdbec6SFrançois Tigeot 	IICBB_SETSDA(bridge_dev, 1);
348a2fdbec6SFrançois Tigeot 	IICBB_SETSCL(bridge_dev, 1);
349a2fdbec6SFrançois Tigeot 	intel_i2c_quirk_set(dev_priv, false);
350a2fdbec6SFrançois Tigeot 
351a2fdbec6SFrançois Tigeot 	return (ret);
352a2fdbec6SFrançois Tigeot }
353a2fdbec6SFrançois Tigeot 
354a2fdbec6SFrançois Tigeot static int
355a2fdbec6SFrançois Tigeot gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
356a2fdbec6SFrançois Tigeot 		     u32 gmbus2_status,
357a2fdbec6SFrançois Tigeot 		     u32 gmbus4_irq_en)
358a2fdbec6SFrançois Tigeot {
359a2fdbec6SFrançois Tigeot 	int i;
360a2fdbec6SFrançois Tigeot 	int reg_offset = dev_priv->gpio_mmio_base;
361a2fdbec6SFrançois Tigeot 	u32 gmbus2 = 0;
362a2fdbec6SFrançois Tigeot 	DEFINE_WAIT(wait);
363a2fdbec6SFrançois Tigeot 
364a2fdbec6SFrançois Tigeot 	if (!HAS_GMBUS_IRQ(dev_priv->dev))
365a2fdbec6SFrançois Tigeot 		gmbus4_irq_en = 0;
366a2fdbec6SFrançois Tigeot 
367a2fdbec6SFrançois Tigeot 	/* Important: The hw handles only the first bit, so set only one! Since
368a2fdbec6SFrançois Tigeot 	 * we also need to check for NAKs besides the hw ready/idle signal, we
369a2fdbec6SFrançois Tigeot 	 * need to wake up periodically and check that ourselves. */
370a2fdbec6SFrançois Tigeot 	I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en);
371a2fdbec6SFrançois Tigeot 
3728e26cdf6SFrançois Tigeot 	for (i = 0; i < msecs_to_jiffies_timeout(50); i++) {
373a2fdbec6SFrançois Tigeot 		prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait,
374a2fdbec6SFrançois Tigeot 				TASK_UNINTERRUPTIBLE);
375a2fdbec6SFrançois Tigeot 
376a2fdbec6SFrançois Tigeot 		gmbus2 = I915_READ_NOTRACE(GMBUS2 + reg_offset);
377a2fdbec6SFrançois Tigeot 		if (gmbus2 & (GMBUS_SATOER | gmbus2_status))
378a2fdbec6SFrançois Tigeot 			break;
379a2fdbec6SFrançois Tigeot 
380a2fdbec6SFrançois Tigeot 		schedule_timeout(1);
381a2fdbec6SFrançois Tigeot 	}
382a2fdbec6SFrançois Tigeot 	finish_wait(&dev_priv->gmbus_wait_queue, &wait);
383a2fdbec6SFrançois Tigeot 
384a2fdbec6SFrançois Tigeot 	I915_WRITE(GMBUS4 + reg_offset, 0);
385a2fdbec6SFrançois Tigeot 
386a2fdbec6SFrançois Tigeot 	if (gmbus2 & GMBUS_SATOER)
387a2fdbec6SFrançois Tigeot 		return -ENXIO;
388a2fdbec6SFrançois Tigeot 	if (gmbus2 & gmbus2_status)
389a2fdbec6SFrançois Tigeot 		return 0;
390a2fdbec6SFrançois Tigeot 	return -ETIMEDOUT;
391a2fdbec6SFrançois Tigeot }
392a2fdbec6SFrançois Tigeot 
393a2fdbec6SFrançois Tigeot static int
394a2fdbec6SFrançois Tigeot gmbus_wait_idle(struct drm_i915_private *dev_priv)
395a2fdbec6SFrançois Tigeot {
396a2fdbec6SFrançois Tigeot 	int ret;
397a2fdbec6SFrançois Tigeot 	int reg_offset = dev_priv->gpio_mmio_base;
398a2fdbec6SFrançois Tigeot 
399a2fdbec6SFrançois Tigeot #define C ((I915_READ_NOTRACE(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0)
400a2fdbec6SFrançois Tigeot 
401a2fdbec6SFrançois Tigeot 	if (!HAS_GMBUS_IRQ(dev_priv->dev))
402a2fdbec6SFrançois Tigeot 		return wait_for(C, 10);
403a2fdbec6SFrançois Tigeot 
404a2fdbec6SFrançois Tigeot 	/* Important: The hw handles only the first bit, so set only one! */
405a2fdbec6SFrançois Tigeot 	I915_WRITE(GMBUS4 + reg_offset, GMBUS_IDLE_EN);
406a2fdbec6SFrançois Tigeot 
4078e26cdf6SFrançois Tigeot 	ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C,
4088e26cdf6SFrançois Tigeot 				 msecs_to_jiffies_timeout(10));
409a2fdbec6SFrançois Tigeot 
410a2fdbec6SFrançois Tigeot 	I915_WRITE(GMBUS4 + reg_offset, 0);
411a2fdbec6SFrançois Tigeot 
412a2fdbec6SFrançois Tigeot 	if (ret)
413a2fdbec6SFrançois Tigeot 		return 0;
414a2fdbec6SFrançois Tigeot 	else
415a2fdbec6SFrançois Tigeot 		return -ETIMEDOUT;
416a2fdbec6SFrançois Tigeot #undef C
417a2fdbec6SFrançois Tigeot }
418a2fdbec6SFrançois Tigeot 
419a2fdbec6SFrançois Tigeot static int
420a2fdbec6SFrançois Tigeot gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
421a2fdbec6SFrançois Tigeot 		u32 gmbus1_index)
422a2fdbec6SFrançois Tigeot {
423a2fdbec6SFrançois Tigeot 	int reg_offset = dev_priv->gpio_mmio_base;
424a2fdbec6SFrançois Tigeot 	u16 len = msg->len;
425a2fdbec6SFrançois Tigeot 	u8 *buf = msg->buf;
426a2fdbec6SFrançois Tigeot 
427a2fdbec6SFrançois Tigeot 	I915_WRITE(GMBUS1 + reg_offset,
428a2fdbec6SFrançois Tigeot 		   gmbus1_index |
429a2fdbec6SFrançois Tigeot 		   GMBUS_CYCLE_WAIT |
430a2fdbec6SFrançois Tigeot 		   (len << GMBUS_BYTE_COUNT_SHIFT) |
431a2fdbec6SFrançois Tigeot 		   (msg->slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) |
432a2fdbec6SFrançois Tigeot 		   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
433a2fdbec6SFrançois Tigeot 	while (len) {
434a2fdbec6SFrançois Tigeot 		int ret;
435a2fdbec6SFrançois Tigeot 		u32 val, loop = 0;
436a2fdbec6SFrançois Tigeot 
437a2fdbec6SFrançois Tigeot 		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
438a2fdbec6SFrançois Tigeot 					   GMBUS_HW_RDY_EN);
439a2fdbec6SFrançois Tigeot 		if (ret)
440a2fdbec6SFrançois Tigeot 			return ret;
441a2fdbec6SFrançois Tigeot 
442a2fdbec6SFrançois Tigeot 		val = I915_READ(GMBUS3 + reg_offset);
443a2fdbec6SFrançois Tigeot 		do {
444a2fdbec6SFrançois Tigeot 			*buf++ = val & 0xff;
445a2fdbec6SFrançois Tigeot 			val >>= 8;
446a2fdbec6SFrançois Tigeot 		} while (--len && ++loop < 4);
447a2fdbec6SFrançois Tigeot 	}
448a2fdbec6SFrançois Tigeot 
449a2fdbec6SFrançois Tigeot 	return 0;
450a2fdbec6SFrançois Tigeot }
451a2fdbec6SFrançois Tigeot 
452a2fdbec6SFrançois Tigeot static int
453a2fdbec6SFrançois Tigeot gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
454a2fdbec6SFrançois Tigeot {
455a2fdbec6SFrançois Tigeot 	int reg_offset = dev_priv->gpio_mmio_base;
456a2fdbec6SFrançois Tigeot 	u16 len = msg->len;
457a2fdbec6SFrançois Tigeot 	u8 *buf = msg->buf;
458bad0eccaSFrançois Tigeot 	u32 val, loop;
459bad0eccaSFrançois Tigeot 
460a2fdbec6SFrançois Tigeot 	val = loop = 0;
461a2fdbec6SFrançois Tigeot 	while (len && loop < 4) {
462a2fdbec6SFrançois Tigeot 		val |= *buf++ << (8 * loop++);
463a2fdbec6SFrançois Tigeot 		len -= 1;
464a2fdbec6SFrançois Tigeot 	}
465a2fdbec6SFrançois Tigeot 
466a2fdbec6SFrançois Tigeot 	I915_WRITE(GMBUS3 + reg_offset, val);
467a2fdbec6SFrançois Tigeot 	I915_WRITE(GMBUS1 + reg_offset,
468a2fdbec6SFrançois Tigeot 		   GMBUS_CYCLE_WAIT |
469a2fdbec6SFrançois Tigeot 		   (msg->len << GMBUS_BYTE_COUNT_SHIFT) |
470a2fdbec6SFrançois Tigeot 		   (msg->slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) |
471a2fdbec6SFrançois Tigeot 		   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
472a2fdbec6SFrançois Tigeot 	while (len) {
473a2fdbec6SFrançois Tigeot 		int ret;
474a2fdbec6SFrançois Tigeot 
475a2fdbec6SFrançois Tigeot 		val = loop = 0;
476a2fdbec6SFrançois Tigeot 		do {
477a2fdbec6SFrançois Tigeot 			val |= *buf++ << (8 * loop);
478a2fdbec6SFrançois Tigeot 		} while (--len && ++loop < 4);
479a2fdbec6SFrançois Tigeot 
480a2fdbec6SFrançois Tigeot 		I915_WRITE(GMBUS3 + reg_offset, val);
481a2fdbec6SFrançois Tigeot 
482a2fdbec6SFrançois Tigeot 		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
483a2fdbec6SFrançois Tigeot 					   GMBUS_HW_RDY_EN);
484a2fdbec6SFrançois Tigeot 		if (ret)
485a2fdbec6SFrançois Tigeot 			return ret;
486a2fdbec6SFrançois Tigeot 	}
487a2fdbec6SFrançois Tigeot 	return 0;
488a2fdbec6SFrançois Tigeot }
489a2fdbec6SFrançois Tigeot 
490a2fdbec6SFrançois Tigeot /*
491a2fdbec6SFrançois Tigeot  * The gmbus controller can combine a 1 or 2 byte write with a read that
492a2fdbec6SFrançois Tigeot  * immediately follows it by using an "INDEX" cycle.
493a2fdbec6SFrançois Tigeot  */
494a2fdbec6SFrançois Tigeot static bool
495a2fdbec6SFrançois Tigeot gmbus_is_index_read(struct i2c_msg *msgs, int i, int num)
496a2fdbec6SFrançois Tigeot {
497a2fdbec6SFrançois Tigeot 	return (i + 1 < num &&
498a2fdbec6SFrançois Tigeot 		!(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 &&
499a2fdbec6SFrançois Tigeot 		(msgs[i + 1].flags & I2C_M_RD));
500a2fdbec6SFrançois Tigeot }
501a2fdbec6SFrançois Tigeot 
502a2fdbec6SFrançois Tigeot static int
503a2fdbec6SFrançois Tigeot gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
504a2fdbec6SFrançois Tigeot {
505a2fdbec6SFrançois Tigeot 	int reg_offset = dev_priv->gpio_mmio_base;
506a2fdbec6SFrançois Tigeot 	u32 gmbus1_index = 0;
507a2fdbec6SFrançois Tigeot 	u32 gmbus5 = 0;
508a2fdbec6SFrançois Tigeot 	int ret;
509a2fdbec6SFrançois Tigeot 
510a2fdbec6SFrançois Tigeot 	if (msgs[0].len == 2)
511a2fdbec6SFrançois Tigeot 		gmbus5 = GMBUS_2BYTE_INDEX_EN |
512a2fdbec6SFrançois Tigeot 			 msgs[0].buf[1] | (msgs[0].buf[0] << 8);
513a2fdbec6SFrançois Tigeot 	if (msgs[0].len == 1)
514a2fdbec6SFrançois Tigeot 		gmbus1_index = GMBUS_CYCLE_INDEX |
515a2fdbec6SFrançois Tigeot 			       (msgs[0].buf[0] << GMBUS_SLAVE_INDEX_SHIFT);
516a2fdbec6SFrançois Tigeot 
517a2fdbec6SFrançois Tigeot 	/* GMBUS5 holds 16-bit index */
518a2fdbec6SFrançois Tigeot 	if (gmbus5)
519a2fdbec6SFrançois Tigeot 		I915_WRITE(GMBUS5 + reg_offset, gmbus5);
520a2fdbec6SFrançois Tigeot 
521a2fdbec6SFrançois Tigeot 	ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
522a2fdbec6SFrançois Tigeot 
523a2fdbec6SFrançois Tigeot 	/* Clear GMBUS5 after each index transfer */
524a2fdbec6SFrançois Tigeot 	if (gmbus5)
525a2fdbec6SFrançois Tigeot 		I915_WRITE(GMBUS5 + reg_offset, 0);
526a2fdbec6SFrançois Tigeot 
527a2fdbec6SFrançois Tigeot 	return ret;
528a2fdbec6SFrançois Tigeot }
529a2fdbec6SFrançois Tigeot 
530a2fdbec6SFrançois Tigeot static int
531a2fdbec6SFrançois Tigeot gmbus_xfer(struct device *adapter,
532a2fdbec6SFrançois Tigeot 	   struct i2c_msg *msgs,
533a2fdbec6SFrançois Tigeot 	   int num)
534a2fdbec6SFrançois Tigeot {
535a2fdbec6SFrançois Tigeot 	struct intel_iic_softc *sc;
536a2fdbec6SFrançois Tigeot 	struct drm_i915_private *dev_priv;
537a2fdbec6SFrançois Tigeot 	int i, reg_offset, unit;
538a2fdbec6SFrançois Tigeot 	int ret = 0;
539a2fdbec6SFrançois Tigeot 
540a2fdbec6SFrançois Tigeot 	sc = device_get_softc(adapter);
541bad0eccaSFrançois Tigeot 	dev_priv = sc->drm_dev->dev_private;
542a2fdbec6SFrançois Tigeot 	unit = device_get_unit(adapter);
543bad0eccaSFrançois Tigeot 
544a2fdbec6SFrançois Tigeot 	mutex_lock(&dev_priv->gmbus_mutex);
545a2fdbec6SFrançois Tigeot 
546bad0eccaSFrançois Tigeot 	if (sc->force_bit_dev) {
547a2fdbec6SFrançois Tigeot 		ret = intel_i2c_quirk_xfer(dev_priv->bbbus[unit], msgs, num);
548bad0eccaSFrançois Tigeot 		goto out;
549bad0eccaSFrançois Tigeot 	}
550bad0eccaSFrançois Tigeot 
551bad0eccaSFrançois Tigeot 	reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
552bad0eccaSFrançois Tigeot 
553bad0eccaSFrançois Tigeot 	I915_WRITE(GMBUS0 + reg_offset, sc->reg0);
554bad0eccaSFrançois Tigeot 
555a2fdbec6SFrançois Tigeot 	for (i = 0; i < num; i++) {
556a2fdbec6SFrançois Tigeot 		if (gmbus_is_index_read(msgs, i, num)) {
557a2fdbec6SFrançois Tigeot 			ret = gmbus_xfer_index_read(dev_priv, &msgs[i]);
558a2fdbec6SFrançois Tigeot 			i += 1;  /* set i to the index of the read xfer */
559a2fdbec6SFrançois Tigeot 		} else if (msgs[i].flags & I2C_M_RD) {
560a2fdbec6SFrançois Tigeot 			ret = gmbus_xfer_read(dev_priv, &msgs[i], 0);
561bad0eccaSFrançois Tigeot 		} else {
562a2fdbec6SFrançois Tigeot 			ret = gmbus_xfer_write(dev_priv, &msgs[i]);
563a2fdbec6SFrançois Tigeot 		}
564bad0eccaSFrançois Tigeot 
565a2fdbec6SFrançois Tigeot 		if (ret == -ETIMEDOUT)
566bad0eccaSFrançois Tigeot 			goto timeout;
567a2fdbec6SFrançois Tigeot 		if (ret == -ENXIO)
568bad0eccaSFrançois Tigeot 			goto clear_err;
569bad0eccaSFrançois Tigeot 
570a2fdbec6SFrançois Tigeot 		ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE,
571a2fdbec6SFrançois Tigeot 					   GMBUS_HW_WAIT_EN);
572a2fdbec6SFrançois Tigeot 		if (ret == -ENXIO)
573bad0eccaSFrançois Tigeot 			goto clear_err;
574a2fdbec6SFrançois Tigeot 		if (ret)
575a2fdbec6SFrançois Tigeot 			goto timeout;
576bad0eccaSFrançois Tigeot 	}
577bad0eccaSFrançois Tigeot 
578a2fdbec6SFrançois Tigeot 	/* Generate a STOP condition on the bus. Note that gmbus can't generata
579a2fdbec6SFrançois Tigeot 	 * a STOP on the very first cycle. To simplify the code we
580a2fdbec6SFrançois Tigeot 	 * unconditionally generate the STOP condition with an additional gmbus
581a2fdbec6SFrançois Tigeot 	 * cycle. */
582a2fdbec6SFrançois Tigeot 	I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
583a2fdbec6SFrançois Tigeot 
584bad0eccaSFrançois Tigeot 	/* Mark the GMBUS interface as disabled after waiting for idle.
585bad0eccaSFrançois Tigeot 	 * We will re-enable it at the start of the next xfer,
586bad0eccaSFrançois Tigeot 	 * till then let it sleep.
587bad0eccaSFrançois Tigeot 	 */
588a2fdbec6SFrançois Tigeot 	if (gmbus_wait_idle(dev_priv)) {
589a2fdbec6SFrançois Tigeot 		DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n",
590a2fdbec6SFrançois Tigeot 			 sc->name);
591a2fdbec6SFrançois Tigeot 		ret = -ETIMEDOUT;
592a2fdbec6SFrançois Tigeot 	}
593bad0eccaSFrançois Tigeot 	I915_WRITE(GMBUS0 + reg_offset, 0);
594a2fdbec6SFrançois Tigeot 	ret = ret ?: i;
595a2fdbec6SFrançois Tigeot 	goto timeout;	/* XXX: should be out */
596bad0eccaSFrançois Tigeot 
597bad0eccaSFrançois Tigeot clear_err:
598a2fdbec6SFrançois Tigeot 	/*
599a2fdbec6SFrançois Tigeot 	 * Wait for bus to IDLE before clearing NAK.
600a2fdbec6SFrançois Tigeot 	 * If we clear the NAK while bus is still active, then it will stay
601a2fdbec6SFrançois Tigeot 	 * active and the next transaction may fail.
602a2fdbec6SFrançois Tigeot 	 *
603a2fdbec6SFrançois Tigeot 	 * If no ACK is received during the address phase of a transaction, the
604a2fdbec6SFrançois Tigeot 	 * adapter must report -ENXIO. It is not clear what to return if no ACK
605a2fdbec6SFrançois Tigeot 	 * is received at other times. But we have to be careful to not return
606a2fdbec6SFrançois Tigeot 	 * spurious -ENXIO because that will prevent i2c and drm edid functions
607a2fdbec6SFrançois Tigeot 	 * from retrying. So return -ENXIO only when gmbus properly quiescents -
608a2fdbec6SFrançois Tigeot 	 * timing out seems to happen when there _is_ a ddc chip present, but
609a2fdbec6SFrançois Tigeot 	 * it's slow responding and only answers on the 2nd retry.
610a2fdbec6SFrançois Tigeot 	 */
611a2fdbec6SFrançois Tigeot 	ret = -ENXIO;
612a2fdbec6SFrançois Tigeot 	if (gmbus_wait_idle(dev_priv)) {
613a2fdbec6SFrançois Tigeot 		DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n",
614a2fdbec6SFrançois Tigeot 			      sc->name);
615a2fdbec6SFrançois Tigeot 		ret = -ETIMEDOUT;
616a2fdbec6SFrançois Tigeot 	}
617a2fdbec6SFrançois Tigeot 
618bad0eccaSFrançois Tigeot 	/* Toggle the Software Clear Interrupt bit. This has the effect
619bad0eccaSFrançois Tigeot 	 * of resetting the GMBUS controller and so clearing the
620bad0eccaSFrançois Tigeot 	 * BUS_ERROR raised by the slave's NAK.
621bad0eccaSFrançois Tigeot 	 */
622bad0eccaSFrançois Tigeot 	I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT);
623bad0eccaSFrançois Tigeot 	I915_WRITE(GMBUS1 + reg_offset, 0);
624bad0eccaSFrançois Tigeot 	I915_WRITE(GMBUS0 + reg_offset, 0);
625bad0eccaSFrançois Tigeot 
626a2fdbec6SFrançois Tigeot 	DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
627a2fdbec6SFrançois Tigeot 			 sc->name, msgs[i].slave,
628a2fdbec6SFrançois Tigeot 			 (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len);
629bad0eccaSFrançois Tigeot 
630bad0eccaSFrançois Tigeot 	goto out;
631a2fdbec6SFrançois Tigeot 
632a2fdbec6SFrançois Tigeot timeout:
633a2fdbec6SFrançois Tigeot 	DRM_INFO("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
634a2fdbec6SFrançois Tigeot 		 sc->name, sc->reg0 & 0xff);
635a2fdbec6SFrançois Tigeot 	I915_WRITE(GMBUS0 + reg_offset, 0);
636a2fdbec6SFrançois Tigeot 
637a2fdbec6SFrançois Tigeot 	/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
638a2fdbec6SFrançois Tigeot 	sc->force_bit_dev = true;
639a2fdbec6SFrançois Tigeot 	ret = intel_i2c_quirk_xfer(dev_priv->bbbus[unit], msgs, num);
640a2fdbec6SFrançois Tigeot 
641a2fdbec6SFrançois Tigeot out:
642a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev_priv->gmbus_mutex);
643a2fdbec6SFrançois Tigeot 	return ret;
644bad0eccaSFrançois Tigeot }
645bad0eccaSFrançois Tigeot 
64619df918dSFrançois Tigeot struct device *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv,
64719df918dSFrançois Tigeot 					    unsigned port)
64819df918dSFrançois Tigeot {
64919df918dSFrançois Tigeot 	WARN_ON(!intel_gmbus_is_port_valid(port));
65019df918dSFrançois Tigeot 	/* -1 to map pin pair to gmbus index */
65119df918dSFrançois Tigeot 	return (intel_gmbus_is_port_valid(port)) ?
65253f7629eSMarkus Pfeiffer 		dev_priv->gmbus[port-1] : NULL;
65319df918dSFrançois Tigeot }
65419df918dSFrançois Tigeot 
655bad0eccaSFrançois Tigeot void
656bad0eccaSFrançois Tigeot intel_gmbus_set_speed(device_t idev, int speed)
657bad0eccaSFrançois Tigeot {
658bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
659bad0eccaSFrançois Tigeot 
660bad0eccaSFrançois Tigeot 	sc = device_get_softc(device_get_parent(idev));
661bad0eccaSFrançois Tigeot 
662bad0eccaSFrançois Tigeot 	sc->reg0 = (sc->reg0 & ~(0x3 << 8)) | speed;
663bad0eccaSFrançois Tigeot }
664bad0eccaSFrançois Tigeot 
665bad0eccaSFrançois Tigeot void
666bad0eccaSFrançois Tigeot intel_gmbus_force_bit(device_t idev, bool force_bit)
667bad0eccaSFrançois Tigeot {
668bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
669bad0eccaSFrançois Tigeot 
670bad0eccaSFrançois Tigeot 	sc = device_get_softc(device_get_parent(idev));
671a2fdbec6SFrançois Tigeot 	sc->force_bit_dev += force_bit ? 1 : -1;
672a2fdbec6SFrançois Tigeot 	DRM_DEBUG_KMS("%sabling bit-banging on %s. force bit now %d\n",
673a2fdbec6SFrançois Tigeot 		      force_bit ? "en" : "dis", sc->name,
674a2fdbec6SFrançois Tigeot 		      sc->force_bit_dev);
675bad0eccaSFrançois Tigeot }
676bad0eccaSFrançois Tigeot 
677bad0eccaSFrançois Tigeot static int
678bad0eccaSFrançois Tigeot intel_gmbus_probe(device_t dev)
679bad0eccaSFrançois Tigeot {
680bad0eccaSFrançois Tigeot 
681bad0eccaSFrançois Tigeot 	return (BUS_PROBE_SPECIFIC);
682bad0eccaSFrançois Tigeot }
683bad0eccaSFrançois Tigeot 
684bad0eccaSFrançois Tigeot static int
685bad0eccaSFrançois Tigeot intel_gmbus_attach(device_t idev)
686bad0eccaSFrançois Tigeot {
687bad0eccaSFrançois Tigeot 	struct drm_i915_private *dev_priv;
688bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
689bad0eccaSFrançois Tigeot 	int pin;
690bad0eccaSFrançois Tigeot 
691bad0eccaSFrançois Tigeot 	sc = device_get_softc(idev);
692bad0eccaSFrançois Tigeot 	sc->drm_dev = device_get_softc(device_get_parent(idev));
693bad0eccaSFrançois Tigeot 	dev_priv = sc->drm_dev->dev_private;
694bad0eccaSFrançois Tigeot 	pin = device_get_unit(idev);
695bad0eccaSFrançois Tigeot 
696bad0eccaSFrançois Tigeot 	ksnprintf(sc->name, sizeof(sc->name), "gmbus bus %s", gpio_names[pin]);
697bad0eccaSFrançois Tigeot 	device_set_desc(idev, sc->name);
698bad0eccaSFrançois Tigeot 
699bad0eccaSFrançois Tigeot 	/* By default use a conservative clock rate */
70053f7629eSMarkus Pfeiffer 	sc->reg0 = (pin + 1) | GMBUS_RATE_100KHZ;
701bad0eccaSFrançois Tigeot 
702bad0eccaSFrançois Tigeot 	/* XXX force bit banging until GMBUS is fully debugged */
703bad0eccaSFrançois Tigeot 	if (IS_GEN2(sc->drm_dev)) {
704bad0eccaSFrançois Tigeot 		sc->force_bit_dev = true;
705bad0eccaSFrançois Tigeot 	}
706bad0eccaSFrançois Tigeot 
707bad0eccaSFrançois Tigeot 	/* add bus interface device */
708bad0eccaSFrançois Tigeot 	sc->iic_dev = device_add_child(idev, "iicbus", -1);
709bad0eccaSFrançois Tigeot 	if (sc->iic_dev == NULL)
710bad0eccaSFrançois Tigeot 		return (ENXIO);
711bad0eccaSFrançois Tigeot 	device_quiet(sc->iic_dev);
712bad0eccaSFrançois Tigeot 	bus_generic_attach(idev);
713bad0eccaSFrançois Tigeot 
714bad0eccaSFrançois Tigeot 	return (0);
715bad0eccaSFrançois Tigeot }
716bad0eccaSFrançois Tigeot 
717bad0eccaSFrançois Tigeot static int
718bad0eccaSFrançois Tigeot intel_gmbus_detach(device_t idev)
719bad0eccaSFrançois Tigeot {
720bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
721bad0eccaSFrançois Tigeot 	struct drm_i915_private *dev_priv;
722bad0eccaSFrançois Tigeot 	device_t child;
723bad0eccaSFrançois Tigeot 	int u;
724bad0eccaSFrançois Tigeot 
725bad0eccaSFrançois Tigeot 	sc = device_get_softc(idev);
726bad0eccaSFrançois Tigeot 	u = device_get_unit(idev);
727bad0eccaSFrançois Tigeot 	dev_priv = sc->drm_dev->dev_private;
728bad0eccaSFrançois Tigeot 
729bad0eccaSFrançois Tigeot 	child = sc->iic_dev;
730bad0eccaSFrançois Tigeot 	bus_generic_detach(idev);
731bad0eccaSFrançois Tigeot 	if (child != NULL)
732bad0eccaSFrançois Tigeot 		device_delete_child(idev, child);
733bad0eccaSFrançois Tigeot 
734bad0eccaSFrançois Tigeot 	return (0);
735bad0eccaSFrançois Tigeot }
736bad0eccaSFrançois Tigeot 
737bad0eccaSFrançois Tigeot static int
738bad0eccaSFrançois Tigeot intel_iicbb_probe(device_t dev)
739bad0eccaSFrançois Tigeot {
740bad0eccaSFrançois Tigeot 
741bad0eccaSFrançois Tigeot 	return (BUS_PROBE_DEFAULT);
742bad0eccaSFrançois Tigeot }
743bad0eccaSFrançois Tigeot 
744bad0eccaSFrançois Tigeot static int
745bad0eccaSFrançois Tigeot intel_iicbb_detach(device_t idev)
746bad0eccaSFrançois Tigeot {
747bad0eccaSFrançois Tigeot 	struct intel_iic_softc *sc;
748bad0eccaSFrançois Tigeot 	device_t child;
749bad0eccaSFrançois Tigeot 
750bad0eccaSFrançois Tigeot 	sc = device_get_softc(idev);
751bad0eccaSFrançois Tigeot 	child = sc->iic_dev;
752bad0eccaSFrançois Tigeot 	bus_generic_detach(idev);
753bad0eccaSFrançois Tigeot 	if (child)
754bad0eccaSFrançois Tigeot 		device_delete_child(idev, child);
755bad0eccaSFrançois Tigeot 	return (0);
756bad0eccaSFrançois Tigeot }
757bad0eccaSFrançois Tigeot 
758bad0eccaSFrançois Tigeot static device_method_t intel_gmbus_methods[] = {
759bad0eccaSFrançois Tigeot 	DEVMETHOD(device_probe,		intel_gmbus_probe),
760bad0eccaSFrançois Tigeot 	DEVMETHOD(device_attach,	intel_gmbus_attach),
761bad0eccaSFrançois Tigeot 	DEVMETHOD(device_detach,	intel_gmbus_detach),
762bad0eccaSFrançois Tigeot 	DEVMETHOD(iicbus_reset,		intel_iicbus_reset),
763a2fdbec6SFrançois Tigeot 	DEVMETHOD(iicbus_transfer,	gmbus_xfer),
764bad0eccaSFrançois Tigeot 	DEVMETHOD_END
765bad0eccaSFrançois Tigeot };
766bad0eccaSFrançois Tigeot static driver_t intel_gmbus_driver = {
767bad0eccaSFrançois Tigeot 	"intel_gmbus",
768bad0eccaSFrançois Tigeot 	intel_gmbus_methods,
769bad0eccaSFrançois Tigeot 	sizeof(struct intel_iic_softc)
770bad0eccaSFrançois Tigeot };
771bad0eccaSFrançois Tigeot static devclass_t intel_gmbus_devclass;
772bad0eccaSFrançois Tigeot DRIVER_MODULE_ORDERED(intel_gmbus, drm, intel_gmbus_driver,
773bad0eccaSFrançois Tigeot     intel_gmbus_devclass, 0, 0, SI_ORDER_FIRST);
7743a25be87SSascha Wildner DRIVER_MODULE(iicbus, intel_gmbus, iicbus_driver, iicbus_devclass, NULL, NULL);
775bad0eccaSFrançois Tigeot 
776bad0eccaSFrançois Tigeot static device_method_t intel_iicbb_methods[] =	{
777bad0eccaSFrançois Tigeot 	DEVMETHOD(device_probe,		intel_iicbb_probe),
778a2fdbec6SFrançois Tigeot 	DEVMETHOD(device_attach,	intel_gpio_setup),
779bad0eccaSFrançois Tigeot 	DEVMETHOD(device_detach,	intel_iicbb_detach),
780bad0eccaSFrançois Tigeot 
781bad0eccaSFrançois Tigeot 	DEVMETHOD(bus_add_child,	bus_generic_add_child),
782bad0eccaSFrançois Tigeot 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
783bad0eccaSFrançois Tigeot 
784bad0eccaSFrançois Tigeot 	DEVMETHOD(iicbb_callback,	iicbus_null_callback),
785bad0eccaSFrançois Tigeot 	DEVMETHOD(iicbb_reset,		intel_iicbus_reset),
786a2fdbec6SFrançois Tigeot 	DEVMETHOD(iicbb_setsda,		set_data),
787a2fdbec6SFrançois Tigeot 	DEVMETHOD(iicbb_setscl,		set_clock),
788a2fdbec6SFrançois Tigeot 	DEVMETHOD(iicbb_getsda,		get_data),
789a2fdbec6SFrançois Tigeot 	DEVMETHOD(iicbb_getscl,		get_clock),
790bad0eccaSFrançois Tigeot 	DEVMETHOD_END
791bad0eccaSFrançois Tigeot };
792bad0eccaSFrançois Tigeot static driver_t intel_iicbb_driver = {
793bad0eccaSFrançois Tigeot 	"intel_iicbb",
794bad0eccaSFrançois Tigeot 	intel_iicbb_methods,
795bad0eccaSFrançois Tigeot 	sizeof(struct intel_iic_softc)
796bad0eccaSFrançois Tigeot };
797bad0eccaSFrançois Tigeot static devclass_t intel_iicbb_devclass;
798bad0eccaSFrançois Tigeot DRIVER_MODULE_ORDERED(intel_iicbb, drm, intel_iicbb_driver,
799bad0eccaSFrançois Tigeot     intel_iicbb_devclass, 0, 0, SI_ORDER_FIRST);
8003a25be87SSascha Wildner DRIVER_MODULE(iicbb, intel_iicbb, iicbb_driver, iicbb_devclass, NULL, NULL);
801bad0eccaSFrançois Tigeot 
802a2fdbec6SFrançois Tigeot static void intel_teardown_gmbus_m(struct drm_device *dev, int m);
803a2fdbec6SFrançois Tigeot 
804bad0eccaSFrançois Tigeot int
805bad0eccaSFrançois Tigeot intel_setup_gmbus(struct drm_device *dev)
806bad0eccaSFrançois Tigeot {
807a2fdbec6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
808bad0eccaSFrançois Tigeot 	device_t iic_dev;
809bad0eccaSFrançois Tigeot 	int i, ret;
810bad0eccaSFrançois Tigeot 
8118e26cdf6SFrançois Tigeot 	if (HAS_PCH_NOP(dev))
8128e26cdf6SFrançois Tigeot 		return 0;
8138e26cdf6SFrançois Tigeot 	else if (HAS_PCH_SPLIT(dev))
814a2fdbec6SFrançois Tigeot 		dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA;
815a2fdbec6SFrançois Tigeot 	else if (IS_VALLEYVIEW(dev))
816a2fdbec6SFrançois Tigeot 		dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE;
817a2fdbec6SFrançois Tigeot 	else
818a2fdbec6SFrançois Tigeot 		dev_priv->gpio_mmio_base = 0;
819a2fdbec6SFrançois Tigeot 
82019df918dSFrançois Tigeot 	lockinit(&dev_priv->gmbus_mutex, "gmbus", 0, LK_CANRECURSE);
821a2fdbec6SFrançois Tigeot 	init_waitqueue_head(&dev_priv->gmbus_wait_queue);
822a2fdbec6SFrançois Tigeot 
823bad0eccaSFrançois Tigeot 	dev_priv->gmbus_bridge = kmalloc(sizeof(device_t) * GMBUS_NUM_PORTS,
8245a3b77d5SFrançois Tigeot 	    M_DRM, M_WAITOK | M_ZERO);
825bad0eccaSFrançois Tigeot 	dev_priv->bbbus_bridge = kmalloc(sizeof(device_t) * GMBUS_NUM_PORTS,
8265a3b77d5SFrançois Tigeot 	    M_DRM, M_WAITOK | M_ZERO);
827bad0eccaSFrançois Tigeot 	dev_priv->gmbus = kmalloc(sizeof(device_t) * GMBUS_NUM_PORTS,
8285a3b77d5SFrançois Tigeot 	    M_DRM, M_WAITOK | M_ZERO);
829bad0eccaSFrançois Tigeot 	dev_priv->bbbus = kmalloc(sizeof(device_t) * GMBUS_NUM_PORTS,
8305a3b77d5SFrançois Tigeot 	    M_DRM, M_WAITOK | M_ZERO);
831bad0eccaSFrançois Tigeot 
832bad0eccaSFrançois Tigeot 	for (i = 0; i < GMBUS_NUM_PORTS; i++) {
833bad0eccaSFrançois Tigeot 		/*
834bad0eccaSFrançois Tigeot 		 * Initialized bbbus_bridge before gmbus_bridge, since
835bad0eccaSFrançois Tigeot 		 * gmbus may decide to force quirk transfer in the
836bad0eccaSFrançois Tigeot 		 * attachment code.
837bad0eccaSFrançois Tigeot 		 */
838bad0eccaSFrançois Tigeot 		dev_priv->bbbus_bridge[i] = device_add_child(dev->dev,
839bad0eccaSFrançois Tigeot 		    "intel_iicbb", i);
840bad0eccaSFrançois Tigeot 		if (dev_priv->bbbus_bridge[i] == NULL) {
841bad0eccaSFrançois Tigeot 			DRM_ERROR("bbbus bridge %d creation failed\n", i);
842bad0eccaSFrançois Tigeot 			ret = ENXIO;
843bad0eccaSFrançois Tigeot 			goto err;
844bad0eccaSFrançois Tigeot 		}
845bad0eccaSFrançois Tigeot 		device_quiet(dev_priv->bbbus_bridge[i]);
846bad0eccaSFrançois Tigeot 		ret = device_probe_and_attach(dev_priv->bbbus_bridge[i]);
847bad0eccaSFrançois Tigeot 		if (ret != 0) {
848bad0eccaSFrançois Tigeot 			DRM_ERROR("bbbus bridge %d attach failed, %d\n", i,
849bad0eccaSFrançois Tigeot 			    ret);
850bad0eccaSFrançois Tigeot 			goto err;
851bad0eccaSFrançois Tigeot 		}
852bad0eccaSFrançois Tigeot 
853bad0eccaSFrançois Tigeot 		iic_dev = device_find_child(dev_priv->bbbus_bridge[i], "iicbb",
854bad0eccaSFrançois Tigeot 		    -1);
855bad0eccaSFrançois Tigeot 		if (iic_dev == NULL) {
856bad0eccaSFrançois Tigeot 			DRM_ERROR("bbbus bridge doesn't have iicbb child\n");
857bad0eccaSFrançois Tigeot 			goto err;
858bad0eccaSFrançois Tigeot 		}
859bad0eccaSFrançois Tigeot 		iic_dev = device_find_child(iic_dev, "iicbus", -1);
860bad0eccaSFrançois Tigeot 		if (iic_dev == NULL) {
861bad0eccaSFrançois Tigeot 			DRM_ERROR(
862bad0eccaSFrançois Tigeot 		"bbbus bridge doesn't have iicbus grandchild\n");
863bad0eccaSFrançois Tigeot 			goto err;
864bad0eccaSFrançois Tigeot 		}
865bad0eccaSFrançois Tigeot 
866bad0eccaSFrançois Tigeot 		dev_priv->bbbus[i] = iic_dev;
867bad0eccaSFrançois Tigeot 
868bad0eccaSFrançois Tigeot 		dev_priv->gmbus_bridge[i] = device_add_child(dev->dev,
869bad0eccaSFrançois Tigeot 		    "intel_gmbus", i);
870bad0eccaSFrançois Tigeot 		if (dev_priv->gmbus_bridge[i] == NULL) {
871bad0eccaSFrançois Tigeot 			DRM_ERROR("gmbus bridge %d creation failed\n", i);
872bad0eccaSFrançois Tigeot 			ret = ENXIO;
873bad0eccaSFrançois Tigeot 			goto err;
874bad0eccaSFrançois Tigeot 		}
875bad0eccaSFrançois Tigeot 		device_quiet(dev_priv->gmbus_bridge[i]);
876bad0eccaSFrançois Tigeot 		ret = device_probe_and_attach(dev_priv->gmbus_bridge[i]);
877bad0eccaSFrançois Tigeot 		if (ret != 0) {
878bad0eccaSFrançois Tigeot 			DRM_ERROR("gmbus bridge %d attach failed, %d\n", i,
879bad0eccaSFrançois Tigeot 			    ret);
880bad0eccaSFrançois Tigeot 			ret = ENXIO;
881bad0eccaSFrançois Tigeot 			goto err;
882bad0eccaSFrançois Tigeot 		}
883bad0eccaSFrançois Tigeot 
884bad0eccaSFrançois Tigeot 		iic_dev = device_find_child(dev_priv->gmbus_bridge[i],
885bad0eccaSFrançois Tigeot 		    "iicbus", -1);
886bad0eccaSFrançois Tigeot 		if (iic_dev == NULL) {
887bad0eccaSFrançois Tigeot 			DRM_ERROR("gmbus bridge doesn't have iicbus child\n");
888bad0eccaSFrançois Tigeot 			goto err;
889bad0eccaSFrançois Tigeot 		}
890bad0eccaSFrançois Tigeot 		dev_priv->gmbus[i] = iic_dev;
891bad0eccaSFrançois Tigeot 
8923f2f609dSFrançois Tigeot 		intel_i2c_reset(dev);
893bad0eccaSFrançois Tigeot 	}
894bad0eccaSFrançois Tigeot 
895bad0eccaSFrançois Tigeot 	return (0);
896bad0eccaSFrançois Tigeot 
897bad0eccaSFrançois Tigeot err:
898bad0eccaSFrançois Tigeot 	intel_teardown_gmbus_m(dev, i);
899bad0eccaSFrançois Tigeot 	return (ret);
900bad0eccaSFrançois Tigeot }
901bad0eccaSFrançois Tigeot 
902bad0eccaSFrançois Tigeot static void
903bad0eccaSFrançois Tigeot intel_teardown_gmbus_m(struct drm_device *dev, int m)
904bad0eccaSFrançois Tigeot {
905bad0eccaSFrançois Tigeot 	struct drm_i915_private *dev_priv;
906bad0eccaSFrançois Tigeot 
907bad0eccaSFrançois Tigeot 	dev_priv = dev->dev_private;
908bad0eccaSFrançois Tigeot 
9095a3b77d5SFrançois Tigeot 	drm_free(dev_priv->gmbus, M_DRM);
910bad0eccaSFrançois Tigeot 	dev_priv->gmbus = NULL;
9115a3b77d5SFrançois Tigeot 	drm_free(dev_priv->bbbus, M_DRM);
912bad0eccaSFrançois Tigeot 	dev_priv->bbbus = NULL;
9135a3b77d5SFrançois Tigeot 	drm_free(dev_priv->gmbus_bridge, M_DRM);
914bad0eccaSFrançois Tigeot 	dev_priv->gmbus_bridge = NULL;
9155a3b77d5SFrançois Tigeot 	drm_free(dev_priv->bbbus_bridge, M_DRM);
916bad0eccaSFrançois Tigeot 	dev_priv->bbbus_bridge = NULL;
91719df918dSFrançois Tigeot 	lockuninit(&dev_priv->gmbus_mutex);
918bad0eccaSFrançois Tigeot }
919bad0eccaSFrançois Tigeot 
920bad0eccaSFrançois Tigeot void
921bad0eccaSFrançois Tigeot intel_teardown_gmbus(struct drm_device *dev)
922bad0eccaSFrançois Tigeot {
923bad0eccaSFrançois Tigeot 
924bad0eccaSFrançois Tigeot 	get_mplock();
925bad0eccaSFrançois Tigeot 	intel_teardown_gmbus_m(dev, GMBUS_NUM_PORTS);
926bad0eccaSFrançois Tigeot 	rel_mplock();
927bad0eccaSFrançois Tigeot }
928