1 /* 2 * Copyright 2012 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 */ 24 25 #include <subdev/vga.h> 26 27 #include "priv.h" 28 29 struct nv04_i2c_priv { 30 struct nouveau_i2c base; 31 }; 32 33 struct nv04_i2c_port { 34 struct nouveau_i2c_port base; 35 u8 drive; 36 u8 sense; 37 }; 38 39 static void 40 nv04_i2c_drive_scl(struct nouveau_i2c_port *base, int state) 41 { 42 struct nv04_i2c_priv *priv = (void *)nouveau_i2c(base); 43 struct nv04_i2c_port *port = (void *)base; 44 u8 val = nv_rdvgac(priv, 0, port->drive); 45 if (state) val |= 0x20; 46 else val &= 0xdf; 47 nv_wrvgac(priv, 0, port->drive, val | 0x01); 48 } 49 50 static void 51 nv04_i2c_drive_sda(struct nouveau_i2c_port *base, int state) 52 { 53 struct nv04_i2c_priv *priv = (void *)nouveau_i2c(base); 54 struct nv04_i2c_port *port = (void *)base; 55 u8 val = nv_rdvgac(priv, 0, port->drive); 56 if (state) val |= 0x10; 57 else val &= 0xef; 58 nv_wrvgac(priv, 0, port->drive, val | 0x01); 59 } 60 61 static int 62 nv04_i2c_sense_scl(struct nouveau_i2c_port *base) 63 { 64 struct nv04_i2c_priv *priv = (void *)nouveau_i2c(base); 65 struct nv04_i2c_port *port = (void *)base; 66 return !!(nv_rdvgac(priv, 0, port->sense) & 0x04); 67 } 68 69 static int 70 nv04_i2c_sense_sda(struct nouveau_i2c_port *base) 71 { 72 struct nv04_i2c_priv *priv = (void *)nouveau_i2c(base); 73 struct nv04_i2c_port *port = (void *)base; 74 return !!(nv_rdvgac(priv, 0, port->sense) & 0x08); 75 } 76 77 static const struct nouveau_i2c_func 78 nv04_i2c_func = { 79 .drive_scl = nv04_i2c_drive_scl, 80 .drive_sda = nv04_i2c_drive_sda, 81 .sense_scl = nv04_i2c_sense_scl, 82 .sense_sda = nv04_i2c_sense_sda, 83 }; 84 85 static int 86 nv04_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 87 struct nouveau_oclass *oclass, void *data, u32 index, 88 struct nouveau_object **pobject) 89 { 90 struct dcb_i2c_entry *info = data; 91 struct nv04_i2c_port *port; 92 int ret; 93 94 ret = nouveau_i2c_port_create(parent, engine, oclass, index, 95 &nouveau_i2c_bit_algo, &nv04_i2c_func, 96 &port); 97 *pobject = nv_object(port); 98 if (ret) 99 return ret; 100 101 port->drive = info->drive; 102 port->sense = info->sense; 103 return 0; 104 } 105 106 static struct nouveau_oclass 107 nv04_i2c_sclass[] = { 108 { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT), 109 .ofuncs = &(struct nouveau_ofuncs) { 110 .ctor = nv04_i2c_port_ctor, 111 .dtor = _nouveau_i2c_port_dtor, 112 .init = _nouveau_i2c_port_init, 113 .fini = _nouveau_i2c_port_fini, 114 }, 115 }, 116 {} 117 }; 118 119 struct nouveau_oclass * 120 nv04_i2c_oclass = &(struct nouveau_i2c_impl) { 121 .base.handle = NV_SUBDEV(I2C, 0x04), 122 .base.ofuncs = &(struct nouveau_ofuncs) { 123 .ctor = _nouveau_i2c_ctor, 124 .dtor = _nouveau_i2c_dtor, 125 .init = _nouveau_i2c_init, 126 .fini = _nouveau_i2c_fini, 127 }, 128 .sclass = nv04_i2c_sclass, 129 .pad_x = &nv04_i2c_pad_oclass, 130 }.base; 131