radeonfb_i2c.c revision 1.2
1/*- 2 * Copyright (c) 2006 Itronix Inc. 3 * All rights reserved. 4 * 5 * Written by Garrett D'Amore for Itronix Inc. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of Itronix Inc. may not be used to endorse 16 * or promote products derived from this software without specific 17 * prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * ATI Technologies Inc. ("ATI") has not assisted in the creation of, and 34 * does not endorse, this software. ATI will not be responsible or liable 35 * for any actual or alleged damage or loss caused by or in connection with 36 * the use of or reliance on this software. 37 */ 38 39#include <sys/cdefs.h> 40__KERNEL_RCSID(0, "$NetBSD: radeonfb_i2c.c,v 1.2 2007/10/19 12:00:55 ad Exp $"); 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/device.h> 45#include <sys/malloc.h> 46#include <sys/systm.h> 47#include <sys/bus.h> 48 49#include <dev/i2c/i2cvar.h> 50#include <dev/i2c/i2c_bitbang.h> 51#include <dev/i2c/ddcvar.h> 52 53#include <dev/pci/radeonfbreg.h> 54#include <dev/pci/radeonfbvar.h> 55 56/* i2c support */ 57static int radeonfb_i2c_acquire_bus(void *, int); 58static void radeonfb_i2c_release_bus(void *, int); 59static int radeonfb_i2c_send_start(void *, int); 60static int radeonfb_i2c_send_stop(void *, int); 61static int radeonfb_i2c_initiate_xfer(void *, i2c_addr_t, int); 62static int radeonfb_i2c_read_byte(void *, uint8_t *, int); 63static int radeonfb_i2c_write_byte(void *, uint8_t, int); 64 65/* i2c bit-bang glue */ 66static void radeonfb_i2cbb_set_bits(void *, uint32_t); 67static void radeonfb_i2cbb_set_dir(void *, uint32_t); 68static uint32_t radeonfb_i2cbb_read(void *); 69 70/* 71 * I2C bit-bang operations 72 */ 73void 74radeonfb_i2cbb_set_bits(void *cookie, uint32_t bits) 75{ 76 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 77 struct radeonfb_softc *sc = ric->ric_softc; 78 79 PATCH32(sc, ric->ric_register, bits, 80 ~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1)); 81} 82 83void 84radeonfb_i2cbb_set_dir(void *cookie, uint32_t bits) 85{ 86 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 87 struct radeonfb_softc *sc = ric->ric_softc; 88 89 PATCH32(sc, ric->ric_register, bits, ~(RADEON_GPIO_EN_0)); 90} 91 92uint32_t 93radeonfb_i2cbb_read(void *cookie) 94{ 95 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 96 struct radeonfb_softc *sc = ric->ric_softc; 97 98 /* output bit is 0 shifted, input bit is shifted 8 */ 99 return (GET32(sc, ric->ric_register) >> RADEON_GPIO_Y_SHIFT_0); 100} 101 102static const struct i2c_bitbang_ops radeonfb_i2cbb_ops = { 103 radeonfb_i2cbb_set_bits, 104 radeonfb_i2cbb_set_dir, 105 radeonfb_i2cbb_read, 106 { 107 RADEON_GPIO_A_0, /* SDA */ 108 RADEON_GPIO_A_1, /* SCL */ 109 RADEON_GPIO_EN_0, /* SDA output */ 110 0, /* SDA input */ 111 } 112}; 113 114/* 115 * I2C support 116 */ 117int 118radeonfb_i2c_acquire_bus(void *cookie, int flags) 119{ 120 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 121 struct radeonfb_softc *sc = ric->ric_softc; 122 int i; 123 124 /* 125 * Some hardware seems to have hardware/software combined access 126 * to the DVI I2C. We want to use software. 127 */ 128 if (ric->ric_register == RADEON_GPIO_DVI_DDC) { 129 130 /* ask for software access to I2C bus */ 131 SET32(sc, ric->ric_register, RADEON_GPIO_SW_USE); 132 133 /* 134 * wait for the chip to give up access. we don't make 135 * this a hard timeout, because some hardware might 136 * not implement this negotiation protocol 137 */ 138 for (i = RADEON_TIMEOUT; i; i--) { 139 if (GET32(sc, ric->ric_register) & RADEON_GPIO_SW_USE) 140 break; 141 } 142 } 143 144 /* enable the I2C clock */ 145 SET32(sc, ric->ric_register, RADEON_GPIO_EN_1); 146 147 return 0; 148} 149 150void 151radeonfb_i2c_release_bus(void *cookie, int flags) 152{ 153 struct radeonfb_i2c *ric = (struct radeonfb_i2c *)cookie; 154 struct radeonfb_softc *sc = ric->ric_softc; 155 156 if (ric->ric_register == RADEON_GPIO_DVI_DDC) { 157 /* we no longer "want" I2C, and we're "done" with it */ 158 CLR32(sc, ric->ric_register, RADEON_GPIO_SW_USE); 159 SET32(sc, ric->ric_register, RADEON_GPIO_SW_DONE); 160 } 161} 162 163int 164radeonfb_i2c_send_start(void *cookie, int flags) 165{ 166 167 return i2c_bitbang_send_start(cookie, flags, &radeonfb_i2cbb_ops); 168} 169 170int 171radeonfb_i2c_send_stop(void *cookie, int flags) 172{ 173 174 return i2c_bitbang_send_stop(cookie, flags, &radeonfb_i2cbb_ops); 175} 176 177int 178radeonfb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 179{ 180 181 return i2c_bitbang_initiate_xfer(cookie, addr, flags, 182 &radeonfb_i2cbb_ops); 183} 184 185int 186radeonfb_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 187{ 188 189 return i2c_bitbang_read_byte(cookie, valp, flags, &radeonfb_i2cbb_ops); 190} 191 192int 193radeonfb_i2c_write_byte(void *cookie, uint8_t val, int flags) 194{ 195 196 return i2c_bitbang_write_byte(cookie, val, flags, &radeonfb_i2cbb_ops); 197} 198 199void 200radeonfb_i2c_init(struct radeonfb_softc *sc) 201{ 202 int i; 203 204 for (i = 0; i < 4; i++) { 205 struct i2c_controller *icc = &sc->sc_i2c[i].ric_controller; 206 207 sc->sc_i2c[i].ric_softc = sc; 208 icc->ic_cookie = &sc->sc_i2c[i]; 209 icc->ic_acquire_bus = radeonfb_i2c_acquire_bus; 210 icc->ic_release_bus = radeonfb_i2c_release_bus; 211 icc->ic_send_start = radeonfb_i2c_send_start; 212 icc->ic_send_stop = radeonfb_i2c_send_stop; 213 icc->ic_initiate_xfer = radeonfb_i2c_initiate_xfer; 214 icc->ic_read_byte = radeonfb_i2c_read_byte; 215 icc->ic_write_byte = radeonfb_i2c_write_byte; 216 } 217 218 /* index == ddctype (RADEON_DDC_XX) - 1 */ 219 sc->sc_i2c[0].ric_register = RADEON_GPIO_MONID; 220 sc->sc_i2c[1].ric_register = RADEON_GPIO_DVI_DDC; 221 sc->sc_i2c[2].ric_register = RADEON_GPIO_VGA_DDC; 222 sc->sc_i2c[3].ric_register = RADEON_GPIO_CRT2_DDC; 223} 224 225int 226radeonfb_i2c_read_edid(struct radeonfb_softc *sc, int ddctype, uint8_t *data) 227{ 228 229 if ((ddctype < 1) || (ddctype > 4)) 230 return EINVAL; 231 232 ddctype--; 233 return (ddc_read_edid(&sc->sc_i2c[ddctype].ric_controller, data, 128)); 234} 235