1 | #ifndef __NOUVEAU_I2C_H__ |
2 | #define __NOUVEAU_I2C_H__ |
3 | |
4 | #include <core/subdev.h> |
5 | #include <core/device.h> |
6 | |
7 | #include <subdev/bios.h> |
8 | #include <subdev/bios/i2c.h> |
9 | |
10 | #define NV_I2C_PORT(n) (0x00 + (n)) |
11 | #define NV_I2C_DEFAULT(n) (0x80 + (n)) |
12 | |
13 | #define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n)) |
14 | #define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) |
15 | #define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) |
16 | |
17 | struct nouveau_i2c_port { |
18 | struct nouveau_object base; |
19 | struct i2c_adapter adapter; |
20 | |
21 | struct list_head head; |
22 | u8 index; |
23 | |
24 | const struct nouveau_i2c_func *func; |
25 | }; |
26 | |
27 | struct nouveau_i2c_func { |
28 | void (*acquire)(struct nouveau_i2c_port *); |
29 | void (*release)(struct nouveau_i2c_port *); |
30 | |
31 | void (*drive_scl)(struct nouveau_i2c_port *, int); |
32 | void (*drive_sda)(struct nouveau_i2c_port *, int); |
33 | int (*sense_scl)(struct nouveau_i2c_port *); |
34 | int (*sense_sda)(struct nouveau_i2c_port *); |
35 | |
36 | int (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8); |
37 | int (*pattern)(struct nouveau_i2c_port *, int pattern); |
38 | int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh); |
39 | int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe); |
40 | }; |
41 | |
42 | #define nouveau_i2c_port_create(p,e,o,i,a,f,d) \ |
43 | nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f), \ |
44 | sizeof(**d), (void **)d) |
45 | #define nouveau_i2c_port_destroy(p) ({ \ |
46 | struct nouveau_i2c_port *port = (p); \ |
47 | _nouveau_i2c_port_dtor(nv_object(i2c)); \ |
48 | }) |
49 | #define nouveau_i2c_port_init(p) \ |
50 | nouveau_object_init(&(p)->base) |
51 | #define nouveau_i2c_port_fini(p,s) \ |
52 | nouveau_object_fini(&(p)->base, (s)) |
53 | |
54 | int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *, |
55 | struct nouveau_oclass *, u8, |
56 | const struct i2c_algorithm *, |
57 | const struct nouveau_i2c_func *, |
58 | int, void **); |
59 | void _nouveau_i2c_port_dtor(struct nouveau_object *); |
60 | #define _nouveau_i2c_port_init nouveau_object_init |
61 | #define _nouveau_i2c_port_fini nouveau_object_fini |
62 | |
63 | struct nouveau_i2c_board_info { |
64 | struct i2c_board_info dev; |
65 | u8 udelay; /* set to 0 to use the standard delay */ |
66 | }; |
67 | |
68 | struct nouveau_i2c { |
69 | struct nouveau_subdev base; |
70 | |
71 | struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); |
72 | struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); |
73 | int (*identify)(struct nouveau_i2c *, int index, |
74 | const char *what, struct nouveau_i2c_board_info *, |
75 | bool (*match)(struct nouveau_i2c_port *, |
76 | struct i2c_board_info *, void *), void *); |
77 | struct list_head ports; |
78 | }; |
79 | |
80 | static inline struct nouveau_i2c * |
81 | nouveau_i2c(void *obj) |
82 | { |
83 | return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C]; |
84 | } |
85 | |
86 | #define nouveau_i2c_create(p,e,o,s,d) \ |
87 | nouveau_i2c_create_((p), (e), (o), (s), sizeof(**d), (void **)d) |
88 | #define nouveau_i2c_destroy(p) ({ \ |
89 | struct nouveau_i2c *i2c = (p); \ |
90 | _nouveau_i2c_dtor(nv_object(i2c)); \ |
91 | }) |
92 | #define nouveau_i2c_init(p) ({ \ |
93 | struct nouveau_i2c *i2c = (p); \ |
94 | _nouveau_i2c_init(nv_object(i2c)); \ |
95 | }) |
96 | #define nouveau_i2c_fini(p,s) ({ \ |
97 | struct nouveau_i2c *i2c = (p); \ |
98 | _nouveau_i2c_fini(nv_object(i2c), (s)); \ |
99 | }) |
100 | |
101 | int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *, |
102 | struct nouveau_oclass *, struct nouveau_oclass *, |
103 | int, void **); |
104 | void _nouveau_i2c_dtor(struct nouveau_object *); |
105 | int _nouveau_i2c_init(struct nouveau_object *); |
106 | int _nouveau_i2c_fini(struct nouveau_object *, bool); |
107 | |
108 | extern struct nouveau_oclass nv04_i2c_oclass; |
109 | extern struct nouveau_oclass nv4e_i2c_oclass; |
110 | extern struct nouveau_oclass nv50_i2c_oclass; |
111 | extern struct nouveau_oclass nv94_i2c_oclass; |
112 | extern struct nouveau_oclass nvd0_i2c_oclass; |
113 | extern struct nouveau_oclass nouveau_anx9805_sclass[]; |
114 | |
115 | extern const struct i2c_algorithm nouveau_i2c_bit_algo; |
116 | extern const struct i2c_algorithm nouveau_i2c_aux_algo; |
117 | |
118 | static inline int |
119 | nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg) |
120 | { |
121 | u8 val; |
122 | struct i2c_msg msgs[] = { |
123 | { .addr = addr, .flags = 0, .len = 1, .buf = ® }, |
124 | { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val }, |
125 | }; |
126 | |
127 | int ret = i2c_transfer(&port->adapter, msgs, 2); |
128 | if (ret != 2) |
129 | return -EIO; |
130 | |
131 | return val; |
132 | } |
133 | |
134 | static inline int |
135 | nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val) |
136 | { |
137 | u8 buf[2] = { reg, val }; |
138 | struct i2c_msg msgs[] = { |
139 | { .addr = addr, .flags = 0, .len = 2, .buf = buf }, |
140 | }; |
141 | |
142 | int ret = i2c_transfer(&port->adapter, msgs, 1); |
143 | if (ret != 1) |
144 | return -EIO; |
145 | |
146 | return 0; |
147 | } |
148 | |
149 | static inline bool |
150 | nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr) |
151 | { |
152 | return nv_rdi2cr(port, addr, 0) >= 0; |
153 | } |
154 | |
155 | int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); |
156 | int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); |
157 | |
158 | #endif |
159 | |