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