Commit 7dcd060c authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/i2c: create proper chipset-specific class implementations

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 46c13c13
......@@ -95,7 +95,11 @@ nouveau-y += core/subdev/gpio/nve0.o
nouveau-y += core/subdev/i2c/base.o
nouveau-y += core/subdev/i2c/aux.o
nouveau-y += core/subdev/i2c/bit.o
nouveau-y += core/subdev/i2c/nv04.o
nouveau-y += core/subdev/i2c/nv4e.o
nouveau-y += core/subdev/i2c/nv50.o
nouveau-y += core/subdev/i2c/nv94.o
nouveau-y += core/subdev/i2c/nvd0.o
nouveau-y += core/subdev/ibus/nvc0.o
nouveau-y += core/subdev/ibus/nve0.o
nouveau-y += core/subdev/instmem/base.o
......
......@@ -15,7 +15,7 @@ struct dcb_i2c_entry {
enum dcb_i2c_type type;
u8 drive;
u8 sense;
u32 data;
u8 share;
};
u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
......
......@@ -10,21 +10,54 @@
#define NV_I2C_PORT(n) (0x00 + (n))
#define NV_I2C_DEFAULT(n) (0x80 + (n))
#define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n))
#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
struct nouveau_i2c_port {
struct nouveau_object base;
struct i2c_adapter adapter;
struct nouveau_i2c *i2c;
struct i2c_algo_bit_data bit;
struct list_head head;
u8 index;
u16 type;
u32 dcb;
u32 drive;
u32 sense;
u32 state;
void (*aux_mux)(struct nouveau_i2c_port *);
const struct nouveau_i2c_func *func;
};
struct nouveau_i2c_func {
void (*acquire)(struct nouveau_i2c_port *);
void (*release)(struct nouveau_i2c_port *);
void (*drive_scl)(struct nouveau_i2c_port *, int);
void (*drive_sda)(struct nouveau_i2c_port *, int);
int (*sense_scl)(struct nouveau_i2c_port *);
int (*sense_sda)(struct nouveau_i2c_port *);
int (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8);
int (*pattern)(struct nouveau_i2c_port *, int pattern);
int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh);
int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
};
#define nouveau_i2c_port_create(p,e,o,i,a,d) \
nouveau_i2c_port_create_((p), (e), (o), (i), (a), \
sizeof(**d), (void **)d)
#define nouveau_i2c_port_destroy(p) ({ \
struct nouveau_i2c_port *port = (p); \
_nouveau_i2c_port_dtor(nv_object(i2c)); \
})
#define nouveau_i2c_port_init(p) \
nouveau_object_init(&(p)->base)
#define nouveau_i2c_port_fini(p,s) \
nouveau_object_fini(&(p)->base, (s))
int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, u8,
const struct i2c_algorithm *, int, void **);
void _nouveau_i2c_port_dtor(struct nouveau_object *);
#define _nouveau_i2c_port_init nouveau_object_init
#define _nouveau_i2c_port_fini nouveau_object_fini
struct nouveau_i2c {
struct nouveau_subdev base;
......@@ -43,24 +76,75 @@ nouveau_i2c(void *obj)
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C];
}
extern struct nouveau_oclass nouveau_i2c_oclass;
#define nouveau_i2c_create(p,e,o,s,d) \
nouveau_i2c_create_((p), (e), (o), (s), sizeof(**d), (void **)d)
#define nouveau_i2c_destroy(p) ({ \
struct nouveau_i2c *i2c = (p); \
_nouveau_i2c_dtor(nv_object(i2c)); \
})
#define nouveau_i2c_init(p) ({ \
struct nouveau_i2c *i2c = (p); \
_nouveau_i2c_init(nv_object(i2c)); \
})
#define nouveau_i2c_fini(p,s) ({ \
struct nouveau_i2c *i2c = (p); \
_nouveau_i2c_fini(nv_object(i2c), (s)); \
})
void nouveau_i2c_drive_scl(void *, int);
void nouveau_i2c_drive_sda(void *, int);
int nouveau_i2c_sense_scl(void *);
int nouveau_i2c_sense_sda(void *);
int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, struct nouveau_oclass *,
int, void **);
void _nouveau_i2c_dtor(struct nouveau_object *);
int _nouveau_i2c_init(struct nouveau_object *);
int _nouveau_i2c_fini(struct nouveau_object *, bool);
int nv_rdi2cr(struct nouveau_i2c_port *, u8 addr, u8 reg);
int nv_wri2cr(struct nouveau_i2c_port *, u8 addr, u8 reg, u8 val);
bool nv_probe_i2c(struct nouveau_i2c_port *, u8 addr);
int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
extern struct nouveau_oclass nv04_i2c_oclass;
extern struct nouveau_oclass nv4e_i2c_oclass;
extern struct nouveau_oclass nv50_i2c_oclass;
extern struct nouveau_oclass nv94_i2c_oclass;
extern struct nouveau_oclass nvd0_i2c_oclass;
extern const struct i2c_algorithm nouveau_i2c_bit_algo;
extern const struct i2c_algorithm nouveau_i2c_aux_algo;
void nv94_aux_mux(struct nouveau_i2c_port *);
int nv94_aux(struct nouveau_i2c_port *, u8, u32, u8 *, u8);
static inline int
nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
{
u8 val;
struct i2c_msg msgs[] = {
{ .addr = addr, .flags = 0, .len = 1, .buf = &reg },
{ .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
};
int ret = i2c_transfer(&port->adapter, msgs, 2);
if (ret != 2)
return -EIO;
return val;
}
static inline int
nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val)
{
u8 buf[2] = { reg, val };
struct i2c_msg msgs[] = {
{ .addr = addr, .flags = 0, .len = 2, .buf = buf },
};
int ret = i2c_transfer(&port->adapter, msgs, 1);
if (ret != 1)
return -EIO;
return 0;
}
static inline bool
nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr)
{
return nv_rdi2cr(port, addr, 0) >= 0;
}
int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
#endif
......@@ -70,12 +70,12 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
u8 ver, len;
u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
if (ent) {
info->data = nv_ro32(bios, ent + 0);
info->type = nv_ro08(bios, ent + 3);
info->share = DCB_I2C_UNUSED;
if (ver < 0x30) {
info->type &= 0x07;
if (info->type == 0x07)
info->type = 0xff;
info->type = DCB_I2C_UNUSED;
}
switch (info->type) {
......@@ -88,7 +88,11 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
return 0;
case DCB_I2C_NVIO_BIT:
case DCB_I2C_NVIO_AUX:
info->drive = nv_ro08(bios, ent + 0);
info->drive = nv_ro08(bios, ent + 0) & 0x0f;
if (nv_ro08(bios, ent + 1) & 0x01) {
info->share = nv_ro08(bios, ent + 1) >> 1;
info->share &= 0x0f;
}
return 0;
case DCB_I2C_UNUSED:
return 0;
......@@ -122,6 +126,7 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
}
info->type = DCB_I2C_NV04_BIT;
info->share = DCB_I2C_UNUSED;
return 0;
}
......
......@@ -47,7 +47,7 @@ nv04_identify(struct nouveau_device *device)
case 0x04:
device->cname = "NV04";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv04_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -65,7 +65,7 @@ nv04_identify(struct nouveau_device *device)
case 0x05:
device->cname = "NV05";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv05_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......
......@@ -49,7 +49,7 @@ nv10_identify(struct nouveau_device *device)
device->cname = "NV10";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -66,7 +66,7 @@ nv10_identify(struct nouveau_device *device)
device->cname = "NV15";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -85,7 +85,7 @@ nv10_identify(struct nouveau_device *device)
device->cname = "NV16";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -104,7 +104,7 @@ nv10_identify(struct nouveau_device *device)
device->cname = "nForce";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -123,7 +123,7 @@ nv10_identify(struct nouveau_device *device)
device->cname = "NV11";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -142,7 +142,7 @@ nv10_identify(struct nouveau_device *device)
device->cname = "NV17";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -161,7 +161,7 @@ nv10_identify(struct nouveau_device *device)
device->cname = "nForce2";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -180,7 +180,7 @@ nv10_identify(struct nouveau_device *device)
device->cname = "NV18";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......
......@@ -50,7 +50,7 @@ nv20_identify(struct nouveau_device *device)
device->cname = "NV20";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -69,7 +69,7 @@ nv20_identify(struct nouveau_device *device)
device->cname = "NV25";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -88,7 +88,7 @@ nv20_identify(struct nouveau_device *device)
device->cname = "NV28";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -107,7 +107,7 @@ nv20_identify(struct nouveau_device *device)
device->cname = "NV2A";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......
......@@ -50,7 +50,7 @@ nv30_identify(struct nouveau_device *device)
device->cname = "NV30";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -69,7 +69,7 @@ nv30_identify(struct nouveau_device *device)
device->cname = "NV35";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -88,7 +88,7 @@ nv30_identify(struct nouveau_device *device)
device->cname = "NV31";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -108,7 +108,7 @@ nv30_identify(struct nouveau_device *device)
device->cname = "NV36";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......@@ -128,7 +128,7 @@ nv30_identify(struct nouveau_device *device)
device->cname = "NV34";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
......
......@@ -52,7 +52,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "NV40";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -73,7 +73,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "NV41";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -94,7 +94,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "NV42";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -115,7 +115,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "NV43";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -136,7 +136,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "NV45";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -157,7 +157,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "G70";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -178,7 +178,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "G71";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -199,7 +199,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "G73";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -220,7 +220,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "NV44";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -241,7 +241,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "G72";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -262,7 +262,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "NV44A";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -283,7 +283,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "C61";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -304,7 +304,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "C51";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv4e_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -325,7 +325,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "C73";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -346,7 +346,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "C67";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......@@ -367,7 +367,7 @@ nv40_identify(struct nouveau_device *device)
device->cname = "C68";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
......
......@@ -58,7 +58,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "G80";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -81,7 +81,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "G84";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -107,7 +107,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "G86";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -133,7 +133,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "G92";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -159,7 +159,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "G94";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -185,7 +185,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "G96";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -211,7 +211,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "G98";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -237,7 +237,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "G200";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -263,7 +263,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "MCP77/MCP78";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -289,7 +289,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "MCP79/MCP7A";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -315,7 +315,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "GT215";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -342,7 +342,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "GT216";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -368,7 +368,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "GT218";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -394,7 +394,7 @@ nv50_identify(struct nouveau_device *device)
device->cname = "MCP89";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......
......@@ -58,7 +58,7 @@ nvc0_identify(struct nouveau_device *device)
device->cname = "GF100";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -87,7 +87,7 @@ nvc0_identify(struct nouveau_device *device)
device->cname = "GF104";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -116,7 +116,7 @@ nvc0_identify(struct nouveau_device *device)
device->cname = "GF106";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -145,7 +145,7 @@ nvc0_identify(struct nouveau_device *device)
device->cname = "GF114";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -174,7 +174,7 @@ nvc0_identify(struct nouveau_device *device)
device->cname = "GF116";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -203,7 +203,7 @@ nvc0_identify(struct nouveau_device *device)
device->cname = "GF108";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -232,7 +232,7 @@ nvc0_identify(struct nouveau_device *device)
device->cname = "GF110";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -261,7 +261,7 @@ nvc0_identify(struct nouveau_device *device)
device->cname = "GF119";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......
......@@ -58,7 +58,7 @@ nve0_identify(struct nouveau_device *device)
device->cname = "GK104";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -87,7 +87,7 @@ nve0_identify(struct nouveau_device *device)
device->cname = "GK107";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -116,7 +116,7 @@ nve0_identify(struct nouveau_device *device)
device->cname = "GK106";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......
......@@ -27,10 +27,10 @@
int
nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
{
if (port->aux) {
if (port->aux_mux)
port->aux_mux(port);
return port->aux(port, 9, addr, data, size);
if (port->func->aux) {
if (port->func->acquire)
port->func->acquire(port);
return port->func->aux(port, 9, addr, data, size);
}
return -ENODEV;
}
......@@ -38,10 +38,10 @@ nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
int
nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
{
if (port->aux) {
if (port->aux_mux)
port->aux_mux(port);
return port->aux(port, 8, addr, data, size);
if (port->func->aux) {
if (port->func->acquire)
port->func->acquire(port);
return port->func->aux(port, 8, addr, data, size);
}
return -ENODEV;
}
......@@ -49,14 +49,14 @@ nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
static int
aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)adap;
struct nouveau_i2c_port *port = adap->algo_data;
struct i2c_msg *msg = msgs;
int ret, mcnt = num;
if (!port->aux)
if (!port->func->aux)
return -ENODEV;
if ( port->aux_mux)
port->aux_mux(port);
if ( port->func->acquire)
port->func->acquire(port);
while (mcnt--) {
u8 remaining = msg->len;
......@@ -74,7 +74,7 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (mcnt || remaining > 16)
cmd |= 4; /* MOT */
ret = port->aux(port, cmd, msg->addr, ptr, cnt);
ret = port->func->aux(port, cmd, msg->addr, ptr, cnt);
if (ret < 0)
return ret;
......
/*
* Copyright 2012 Red Hat Inc.
* Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
......@@ -22,64 +22,133 @@
* Authors: Ben Skeggs
*/
#include "core/option.h"
#include <core/option.h>
#include "subdev/i2c.h"
#include "subdev/vga.h"
#include <subdev/i2c.h>
#include <subdev/vga.h>
int
nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
/******************************************************************************
* interface to linux i2c bit-banging algorithm
*****************************************************************************/
#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
#define CSTMSEL true
#else
#define CSTMSEL false
#endif
static int
nouveau_i2c_pre_xfer(struct i2c_adapter *adap)
{
u8 val;
struct i2c_msg msgs[] = {
{ .addr = addr, .flags = 0, .len = 1, .buf = &reg },
{ .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
};
struct i2c_algo_bit_data *bit = adap->algo_data;
struct nouveau_i2c_port *port = bit->data;
if (port->func->acquire)
port->func->acquire(port);
return 0;
}
int ret = i2c_transfer(&port->adapter, msgs, 2);
if (ret != 2)
return -EIO;
static void
nouveau_i2c_setscl(void *data, int state)
{
struct nouveau_i2c_port *port = data;
port->func->drive_scl(port, state);
}
return val;
static void
nouveau_i2c_setsda(void *data, int state)
{
struct nouveau_i2c_port *port = data;
port->func->drive_sda(port, state);
}
int
nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val)
static int
nouveau_i2c_getscl(void *data)
{
u8 buf[2] = { reg, val };
struct i2c_msg msgs[] = {
{ .addr = addr, .flags = 0, .len = 2, .buf = buf },
};
struct nouveau_i2c_port *port = data;
return port->func->sense_scl(port);
}
static int
nouveau_i2c_getsda(void *data)
{
struct nouveau_i2c_port *port = data;
return port->func->sense_sda(port);
}
int ret = i2c_transfer(&port->adapter, msgs, 1);
if (ret != 1)
return -EIO;
/******************************************************************************
* base i2c "port" class implementation
*****************************************************************************/
return 0;
void
_nouveau_i2c_port_dtor(struct nouveau_object *object)
{
struct nouveau_i2c_port *port = (void *)object;
i2c_del_adapter(&port->adapter);
nouveau_object_destroy(&port->base);
}
bool
nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr)
int
nouveau_i2c_port_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, u8 index,
const struct i2c_algorithm *algo,
int size, void **pobject)
{
u8 buf[] = { 0 };
struct i2c_msg msgs[] = {
{
.addr = addr,
.flags = 0,
.len = 1,
.buf = buf,
},
{
.addr = addr,
.flags = I2C_M_RD,
.len = 1,
.buf = buf,
struct nouveau_device *device = nv_device(parent);
struct nouveau_i2c *i2c = (void *)engine;
struct nouveau_i2c_port *port;
int ret;
ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject);
port = *pobject;
if (ret)
return ret;
snprintf(port->adapter.name, sizeof(port->adapter.name),
"nouveau-%s-%d", device->name, index);
port->adapter.owner = THIS_MODULE;
port->adapter.dev.parent = &device->pdev->dev;
port->index = index;
i2c_set_adapdata(&port->adapter, i2c);
if ( algo == &nouveau_i2c_bit_algo &&
!nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) {
struct i2c_algo_bit_data *bit;
bit = kzalloc(sizeof(*bit), GFP_KERNEL);
if (!bit)
return -ENOMEM;
bit->udelay = 10;
bit->timeout = usecs_to_jiffies(2200);
bit->data = port;
bit->pre_xfer = nouveau_i2c_pre_xfer;
bit->setsda = nouveau_i2c_setsda;
bit->setscl = nouveau_i2c_setscl;
bit->getsda = nouveau_i2c_getsda;
bit->getscl = nouveau_i2c_getscl;
port->adapter.algo_data = bit;
ret = i2c_bit_add_bus(&port->adapter);
} else {
port->adapter.algo_data = port;
port->adapter.algo = algo;
ret = i2c_add_adapter(&port->adapter);
}
};
return i2c_transfer(&port->adapter, msgs, 2) == 2;
/* drop port's i2c subdev refcount, i2c handles this itself */
if (ret == 0) {
list_add_tail(&port->head, &i2c->ports);
atomic_dec(&engine->refcount);
}
return ret;
}
/******************************************************************************
* base i2c subdev class implementation
*****************************************************************************/
static struct nouveau_i2c_port *
nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index)
{
......@@ -115,7 +184,7 @@ nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
struct nouveau_i2c_port *port;
list_for_each_entry(port, &i2c->ports, head) {
if (port->type == type)
if (nv_hclass(port) == type)
return port;
}
......@@ -149,126 +218,78 @@ nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
return -ENODEV;
}
void
nouveau_i2c_drive_scl(void *data, int state)
int
_nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
{
struct nouveau_i2c_port *port = data;
struct nouveau_i2c *i2c = (void *)object;
struct nouveau_i2c_port *port;
int ret;
if (port->type == DCB_I2C_NV04_BIT) {
u8 val = nv_rdvgac(port->i2c, 0, port->drive);
if (state) val |= 0x20;
else val &= 0xdf;
nv_wrvgac(port->i2c, 0, port->drive, val | 0x01);
} else
if (port->type == DCB_I2C_NV4E_BIT) {
nv_mask(port->i2c, port->drive, 0x2f, state ? 0x21 : 0x01);
} else
if (port->type == DCB_I2C_NVIO_BIT) {
if (state) port->state |= 0x01;
else port->state &= 0xfe;
nv_wr32(port->i2c, port->drive, 4 | port->state);
list_for_each_entry(port, &i2c->ports, head) {
ret = nv_ofuncs(port)->fini(nv_object(port), suspend);
if (ret && suspend)
goto fail;
}
}
void
nouveau_i2c_drive_sda(void *data, int state)
{
struct nouveau_i2c_port *port = data;
if (port->type == DCB_I2C_NV04_BIT) {
u8 val = nv_rdvgac(port->i2c, 0, port->drive);
if (state) val |= 0x10;
else val &= 0xef;
nv_wrvgac(port->i2c, 0, port->drive, val | 0x01);
} else
if (port->type == DCB_I2C_NV4E_BIT) {
nv_mask(port->i2c, port->drive, 0x1f, state ? 0x11 : 0x01);
} else
if (port->type == DCB_I2C_NVIO_BIT) {
if (state) port->state |= 0x02;
else port->state &= 0xfd;
nv_wr32(port->i2c, port->drive, 4 | port->state);
return nouveau_subdev_fini(&i2c->base, suspend);
fail:
list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
nv_ofuncs(port)->init(nv_object(port));
}
return ret;
}
int
nouveau_i2c_sense_scl(void *data)
_nouveau_i2c_init(struct nouveau_object *object)
{
struct nouveau_i2c_port *port = data;
struct nouveau_device *device = nv_device(port->i2c);
if (port->type == DCB_I2C_NV04_BIT) {
return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x04);
} else
if (port->type == DCB_I2C_NV4E_BIT) {
return !!(nv_rd32(port->i2c, port->sense) & 0x00040000);
} else
if (port->type == DCB_I2C_NVIO_BIT) {
if (device->card_type < NV_D0)
return !!(nv_rd32(port->i2c, port->sense) & 0x01);
else
return !!(nv_rd32(port->i2c, port->sense) & 0x10);
}
struct nouveau_i2c *i2c = (void *)object;
struct nouveau_i2c_port *port;
int ret;
return 0;
}
ret = nouveau_subdev_init(&i2c->base);
if (ret == 0) {
list_for_each_entry(port, &i2c->ports, head) {
ret = nv_ofuncs(port)->init(nv_object(port));
if (ret)
goto fail;
}
}
int
nouveau_i2c_sense_sda(void *data)
{
struct nouveau_i2c_port *port = data;
struct nouveau_device *device = nv_device(port->i2c);
if (port->type == DCB_I2C_NV04_BIT) {
return !!(nv_rdvgac(port->i2c, 0, port->sense) & 0x08);
} else
if (port->type == DCB_I2C_NV4E_BIT) {
return !!(nv_rd32(port->i2c, port->sense) & 0x00080000);
} else
if (port->type == DCB_I2C_NVIO_BIT) {
if (device->card_type < NV_D0)
return !!(nv_rd32(port->i2c, port->sense) & 0x02);
else
return !!(nv_rd32(port->i2c, port->sense) & 0x20);
return ret;
fail:
list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
nv_ofuncs(port)->fini(nv_object(port), false);
}
return 0;
return ret;
}
static int
nouveau_i2c_pre_xfer(struct i2c_adapter *adap)
void
_nouveau_i2c_dtor(struct nouveau_object *object)
{
struct nouveau_i2c_port *port = (void *)adap;
struct nouveau_i2c *i2c = port->i2c;
if (nv_device(i2c)->card_type >= NV_50 && (port->dcb & 0x00000100)) {
u32 reg = 0x00e500 + ((port->dcb & 0x1e00) >> 9) * 0x50;
/* nfi, but neither auxch or i2c work if it's 1 */
nv_mask(i2c, reg + 0x0c, 0x00000001, 0x00000000);
/* nfi, but switches auxch vs normal i2c */
nv_mask(i2c, reg + 0x00, 0x0000f003, 0x0000e001);
struct nouveau_i2c *i2c = (void *)object;
struct nouveau_i2c_port *port, *temp;
list_for_each_entry_safe(port, temp, &i2c->ports, head) {
nouveau_object_ref(NULL, (struct nouveau_object **)&port);
}
return 0;
nouveau_subdev_destroy(&i2c->base);
}
static const u32 nv50_i2c_port[] = {
0x00e138, 0x00e150, 0x00e168, 0x00e180,
0x00e254, 0x00e274, 0x00e764, 0x00e780,
0x00e79c, 0x00e7b8
};
static int
nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
int
nouveau_i2c_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
struct nouveau_oclass *sclass,
int length, void **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nouveau_bios *bios = nouveau_bios(parent);
struct nouveau_i2c_port *port;
struct nouveau_i2c *i2c;
struct nouveau_object *object;
struct dcb_i2c_entry info;
int ret, i = -1;
int ret, index = -1;
ret = nouveau_subdev_create(parent, engine, oclass, 0,
"I2C", "i2c", &i2c);
......@@ -281,142 +302,20 @@ nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
i2c->identify = nouveau_i2c_identify;
INIT_LIST_HEAD(&i2c->ports);
while (!dcb_i2c_parse(bios, ++i, &info)) {
while (!dcb_i2c_parse(bios, ++index, &info)) {
if (info.type == DCB_I2C_UNUSED)
continue;
port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!port) {
nv_error(i2c, "failed port memory alloc at %d\n", i);
break;
}
port->type = info.type;
switch (port->type) {
case DCB_I2C_NV04_BIT:
port->drive = info.drive;
port->sense = info.sense;
break;
case DCB_I2C_NV4E_BIT:
port->drive = 0x600800 + info.drive;
port->sense = port->drive;
break;
case DCB_I2C_NVIO_BIT:
port->drive = info.drive & 0x0f;
if (device->card_type < NV_D0) {
if (port->drive >= ARRAY_SIZE(nv50_i2c_port))
break;
port->drive = nv50_i2c_port[port->drive];
port->sense = port->drive;
} else {
port->drive = 0x00d014 + (port->drive * 0x20);
port->sense = port->drive;
}
break;
case DCB_I2C_NVIO_AUX:
port->drive = info.drive & 0x0f;
port->sense = port->drive;
port->adapter.algo = &nouveau_i2c_aux_algo;
port->aux_mux = nv94_aux_mux;
port->aux = nv94_aux;
break;
default:
break;
}
if (!port->adapter.algo && !port->drive) {
nv_error(i2c, "I2C%d: type %d index %x/%x unknown\n",
i, port->type, port->drive, port->sense);
kfree(port);
continue;
}
snprintf(port->adapter.name, sizeof(port->adapter.name),
"nouveau-%s-%d", device->name, i);
port->adapter.owner = THIS_MODULE;
port->adapter.dev.parent = &device->pdev->dev;
port->i2c = i2c;
port->index = i;
port->dcb = info.data;
i2c_set_adapdata(&port->adapter, i2c);
if (port->adapter.algo != &nouveau_i2c_aux_algo) {
nouveau_i2c_drive_scl(port, 0);
nouveau_i2c_drive_sda(port, 1);
nouveau_i2c_drive_scl(port, 1);
#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
if (nouveau_boolopt(device->cfgopt, "NvI2C", true)) {
#else
if (nouveau_boolopt(device->cfgopt, "NvI2C", false)) {
#endif
port->adapter.algo = &nouveau_i2c_bit_algo;
ret = i2c_add_adapter(&port->adapter);
} else {
port->adapter.algo_data = &port->bit;
port->bit.udelay = 10;
port->bit.timeout = usecs_to_jiffies(2200);
port->bit.data = port;
port->bit.setsda = nouveau_i2c_drive_sda;
port->bit.setscl = nouveau_i2c_drive_scl;
port->bit.getsda = nouveau_i2c_sense_sda;
port->bit.getscl = nouveau_i2c_sense_scl;
port->bit.pre_xfer = nouveau_i2c_pre_xfer;
ret = i2c_bit_add_bus(&port->adapter);
oclass = sclass;
do {
ret = -EINVAL;
if (oclass->handle == info.type) {
ret = nouveau_object_ctor(*pobject, *pobject,
oclass, &info,
index, &object);
}
} else {
port->adapter.algo = &nouveau_i2c_aux_algo;
ret = i2c_add_adapter(&port->adapter);
}
if (ret) {
nv_error(i2c, "I2C%d: failed register: %d\n", i, ret);
kfree(port);
continue;
}
list_add_tail(&port->head, &i2c->ports);
} while (ret && (++oclass)->handle);
}
return 0;
}
static void
nouveau_i2c_dtor(struct nouveau_object *object)
{
struct nouveau_i2c *i2c = (void *)object;
struct nouveau_i2c_port *port, *temp;
list_for_each_entry_safe(port, temp, &i2c->ports, head) {
i2c_del_adapter(&port->adapter);
list_del(&port->head);
kfree(port);
}
nouveau_subdev_destroy(&i2c->base);
}
static int
nouveau_i2c_init(struct nouveau_object *object)
{
struct nouveau_i2c *i2c = (void *)object;
return nouveau_subdev_init(&i2c->base);
}
static int
nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
{
struct nouveau_i2c *i2c = (void *)object;
return nouveau_subdev_fini(&i2c->base, suspend);
}
struct nouveau_oclass
nouveau_i2c_oclass = {
.handle = NV_SUBDEV(I2C, 0x00),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nouveau_i2c_ctor,
.dtor = nouveau_i2c_dtor,
.init = nouveau_i2c_init,
.fini = nouveau_i2c_fini,
},
};
......@@ -32,25 +32,25 @@
static inline void
i2c_drive_scl(struct nouveau_i2c_port *port, int state)
{
nouveau_i2c_drive_scl(port, state);
port->func->drive_scl(port, state);
}
static inline void
i2c_drive_sda(struct nouveau_i2c_port *port, int state)
{
nouveau_i2c_drive_sda(port, state);
port->func->drive_sda(port, state);
}
static inline int
i2c_sense_scl(struct nouveau_i2c_port *port)
{
return nouveau_i2c_sense_scl(port);
return port->func->sense_scl(port);
}
static inline int
i2c_sense_sda(struct nouveau_i2c_port *port)
{
return nouveau_i2c_sense_sda(port);
return port->func->sense_sda(port);
}
static void
......@@ -77,9 +77,8 @@ i2c_start(struct nouveau_i2c_port *port)
{
int ret = 0;
port->state = i2c_sense_scl(port);
port->state |= i2c_sense_sda(port) << 1;
if (port->state != 3) {
if (!i2c_sense_scl(port) ||
!i2c_sense_sda(port)) {
i2c_drive_scl(port, 0);
i2c_drive_sda(port, 1);
if (!i2c_raise_scl(port))
......@@ -184,10 +183,13 @@ i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg)
static int
i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)adap;
struct nouveau_i2c_port *port = adap->algo_data;
struct i2c_msg *msg = msgs;
int ret = 0, mcnt = num;
if (port->func->acquire)
port->func->acquire(port);
while (!ret && mcnt--) {
u8 remaining = msg->len;
u8 *ptr = msg->buf;
......
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <subdev/i2c.h>
#include <subdev/vga.h>
struct nv04_i2c_priv {
struct nouveau_i2c base;
};
struct nv04_i2c_port {
struct nouveau_i2c_port base;
u8 drive;
u8 sense;
};
static void
nv04_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
{
struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv04_i2c_port *port = (void *)base;
u8 val = nv_rdvgac(priv, 0, port->drive);
if (state) val |= 0x20;
else val &= 0xdf;
nv_wrvgac(priv, 0, port->drive, val | 0x01);
}
static void
nv04_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
{
struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv04_i2c_port *port = (void *)base;
u8 val = nv_rdvgac(priv, 0, port->drive);
if (state) val |= 0x10;
else val &= 0xef;
nv_wrvgac(priv, 0, port->drive, val | 0x01);
}
static int
nv04_i2c_sense_scl(struct nouveau_i2c_port *base)
{
struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv04_i2c_port *port = (void *)base;
return !!(nv_rdvgac(priv, 0, port->sense) & 0x04);
}
static int
nv04_i2c_sense_sda(struct nouveau_i2c_port *base)
{
struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv04_i2c_port *port = (void *)base;
return !!(nv_rdvgac(priv, 0, port->sense) & 0x08);
}
static const struct nouveau_i2c_func
nv04_i2c_func = {
.drive_scl = nv04_i2c_drive_scl,
.drive_sda = nv04_i2c_drive_sda,
.sense_scl = nv04_i2c_sense_scl,
.sense_sda = nv04_i2c_sense_sda,
};
static int
nv04_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 index,
struct nouveau_object **pobject)
{
struct dcb_i2c_entry *info = data;
struct nv04_i2c_port *port;
int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port);
*pobject = nv_object(port);
if (ret)
return ret;
port->base.func = &nv04_i2c_func;
port->drive = info->drive;
port->sense = info->sense;
return 0;
}
static struct nouveau_oclass
nv04_i2c_sclass[] = {
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_i2c_port_ctor,
.dtor = _nouveau_i2c_port_dtor,
.init = _nouveau_i2c_port_init,
.fini = _nouveau_i2c_port_fini,
},
},
{}
};
static int
nv04_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv04_i2c_priv *priv;
int ret;
ret = nouveau_i2c_create(parent, engine, oclass, nv04_i2c_sclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
return 0;
}
struct nouveau_oclass
nv04_i2c_oclass = {
.handle = NV_SUBDEV(I2C, 0x04),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv04_i2c_ctor,
.dtor = _nouveau_i2c_dtor,
.init = _nouveau_i2c_init,
.fini = _nouveau_i2c_fini,
},
};
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <subdev/i2c.h>
#include <subdev/vga.h>
struct nv4e_i2c_priv {
struct nouveau_i2c base;
};
struct nv4e_i2c_port {
struct nouveau_i2c_port base;
u32 addr;
};
static void
nv4e_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
{
struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv4e_i2c_port *port = (void *)base;
nv_mask(priv, port->addr, 0x2f, state ? 0x21 : 0x01);
}
static void
nv4e_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
{
struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv4e_i2c_port *port = (void *)base;
nv_mask(priv, port->addr, 0x1f, state ? 0x11 : 0x01);
}
static int
nv4e_i2c_sense_scl(struct nouveau_i2c_port *base)
{
struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv4e_i2c_port *port = (void *)base;
return !!(nv_rd32(priv, port->addr) & 0x00040000);
}
static int
nv4e_i2c_sense_sda(struct nouveau_i2c_port *base)
{
struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv4e_i2c_port *port = (void *)base;
return !!(nv_rd32(priv, port->addr) & 0x00080000);
}
static const struct nouveau_i2c_func
nv4e_i2c_func = {
.drive_scl = nv4e_i2c_drive_scl,
.drive_sda = nv4e_i2c_drive_sda,
.sense_scl = nv4e_i2c_sense_scl,
.sense_sda = nv4e_i2c_sense_sda,
};
static int
nv4e_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 index,
struct nouveau_object **pobject)
{
struct dcb_i2c_entry *info = data;
struct nv4e_i2c_port *port;
int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port);
*pobject = nv_object(port);
if (ret)
return ret;
port->base.func = &nv4e_i2c_func;
port->addr = 0x600800 + info->drive;
return 0;
}
static struct nouveau_oclass
nv4e_i2c_sclass[] = {
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV4E_BIT),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv4e_i2c_port_ctor,
.dtor = _nouveau_i2c_port_dtor,
.init = _nouveau_i2c_port_init,
.fini = _nouveau_i2c_port_fini,
},
},
{}
};
static int
nv4e_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv4e_i2c_priv *priv;
int ret;
ret = nouveau_i2c_create(parent, engine, oclass, nv4e_i2c_sclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
return 0;
}
struct nouveau_oclass
nv4e_i2c_oclass = {
.handle = NV_SUBDEV(I2C, 0x4e),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv4e_i2c_ctor,
.dtor = _nouveau_i2c_dtor,
.init = _nouveau_i2c_init,
.fini = _nouveau_i2c_fini,
},
};
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
void
nv50_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
{
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv50_i2c_port *port = (void *)base;
if (state) port->state |= 0x01;
else port->state &= 0xfe;
nv_wr32(priv, port->addr, port->state);
}
void
nv50_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
{
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv50_i2c_port *port = (void *)base;
if (state) port->state |= 0x02;
else port->state &= 0xfd;
nv_wr32(priv, port->addr, port->state);
}
int
nv50_i2c_sense_scl(struct nouveau_i2c_port *base)
{
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv50_i2c_port *port = (void *)base;
return !!(nv_rd32(priv, port->addr) & 0x00000001);
}
int
nv50_i2c_sense_sda(struct nouveau_i2c_port *base)
{
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv50_i2c_port *port = (void *)base;
return !!(nv_rd32(priv, port->addr) & 0x00000002);
}
static const struct nouveau_i2c_func
nv50_i2c_func = {
.drive_scl = nv50_i2c_drive_scl,
.drive_sda = nv50_i2c_drive_sda,
.sense_scl = nv50_i2c_sense_scl,
.sense_sda = nv50_i2c_sense_sda,
};
const u32 nv50_i2c_addr[] = {
0x00e138, 0x00e150, 0x00e168, 0x00e180,
0x00e254, 0x00e274, 0x00e764, 0x00e780,
0x00e79c, 0x00e7b8
};
const int nv50_i2c_addr_nr = ARRAY_SIZE(nv50_i2c_addr);
static int
nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 index,
struct nouveau_object **pobject)
{
struct dcb_i2c_entry *info = data;
struct nv50_i2c_port *port;
int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port);
*pobject = nv_object(port);
if (ret)
return ret;
if (info->drive >= nv50_i2c_addr_nr)
return -EINVAL;
port->base.func = &nv50_i2c_func;
port->state = 0x00000007;
port->addr = nv50_i2c_addr[info->drive];
return 0;
}
int
nv50_i2c_port_init(struct nouveau_object *object)
{
struct nv50_i2c_priv *priv = (void *)object->engine;
struct nv50_i2c_port *port = (void *)object;
nv_wr32(priv, port->addr, port->state);
return nouveau_i2c_port_init(&port->base);
}
static struct nouveau_oclass
nv50_i2c_sclass[] = {
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_i2c_port_ctor,
.dtor = _nouveau_i2c_port_dtor,
.init = nv50_i2c_port_init,
.fini = _nouveau_i2c_port_fini,
},
},
{}
};
static int
nv50_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_i2c_priv *priv;
int ret;
ret = nouveau_i2c_create(parent, engine, oclass, nv50_i2c_sclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
return 0;
}
struct nouveau_oclass
nv50_i2c_oclass = {
.handle = NV_SUBDEV(I2C, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_i2c_ctor,
.dtor = _nouveau_i2c_dtor,
.init = _nouveau_i2c_init,
.fini = _nouveau_i2c_fini,
},
};
#ifndef __NV50_I2C_H__
#define __NV50_I2C_H__
#include <subdev/i2c.h>
struct nv50_i2c_priv {
struct nouveau_i2c base;
};
struct nv50_i2c_port {
struct nouveau_i2c_port base;
u32 addr;
u32 ctrl;
u32 data;
u32 state;
};
extern const u32 nv50_i2c_addr[];
extern const int nv50_i2c_addr_nr;
int nv50_i2c_port_init(struct nouveau_object *);
int nv50_i2c_sense_scl(struct nouveau_i2c_port *);
int nv50_i2c_sense_sda(struct nouveau_i2c_port *);
void nv50_i2c_drive_scl(struct nouveau_i2c_port *, int state);
void nv50_i2c_drive_sda(struct nouveau_i2c_port *, int state);
int nv94_aux_port_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
void nv94_i2c_acquire(struct nouveau_i2c_port *);
void nv94_i2c_release(struct nouveau_i2c_port *);
#endif
/*
* Copyright 2009 Red Hat Inc.
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
......@@ -22,11 +22,8 @@
* Authors: Ben Skeggs
*/
#include <subdev/i2c.h>
#include "nv50.h"
/******************************************************************************
* aux channel util functions
*****************************************************************************/
#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
......@@ -72,12 +69,13 @@ auxch_init(struct nouveau_i2c *aux, int ch)
}
int
nv94_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size)
nv94_aux(struct nouveau_i2c_port *base, u8 type, u32 addr, u8 *data, u8 size)
{
struct nouveau_i2c *aux = port->i2c;
struct nouveau_i2c *aux = nouveau_i2c(base);
struct nv50_i2c_port *port = (void *)base;
u32 ctrl, stat, timeout, retries;
u32 xbuf[4] = {};
int ch = port->drive;
int ch = port->addr;
int ret, i;
AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
......@@ -153,13 +151,135 @@ nv94_aux(struct nouveau_i2c_port *port, u8 type, u32 addr, u8 *data, u8 size)
}
void
nv94_aux_mux(struct nouveau_i2c_port *port)
nv94_i2c_acquire(struct nouveau_i2c_port *base)
{
if (port->dcb & 0x00000100) {
u32 reg = 0x00e500 + (port->drive * 0x50);
/* nfi, but neither auxch or i2c work if it's 1 */
nv_mask(port->i2c, reg + 0x0c, 0x00000001, 0x00000000);
/* nfi, but switches auxch vs normal i2c */
nv_mask(port->i2c, reg + 0x00, 0x0000f003, 0x00002002);
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv50_i2c_port *port = (void *)base;
if (port->ctrl) {
nv_mask(priv, port->ctrl + 0x0c, 0x00000001, 0x00000000);
nv_mask(priv, port->ctrl + 0x00, 0x0000f003, port->data);
}
}
void
nv94_i2c_release(struct nouveau_i2c_port *base)
{
}
static const struct nouveau_i2c_func
nv94_i2c_func = {
.acquire = nv94_i2c_acquire,
.release = nv94_i2c_release,
.drive_scl = nv50_i2c_drive_scl,
.drive_sda = nv50_i2c_drive_sda,
.sense_scl = nv50_i2c_sense_scl,
.sense_sda = nv50_i2c_sense_sda,
};
static int
nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 index,
struct nouveau_object **pobject)
{
struct dcb_i2c_entry *info = data;
struct nv50_i2c_port *port;
int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port);
*pobject = nv_object(port);
if (ret)
return ret;
if (info->drive >= nv50_i2c_addr_nr)
return -EINVAL;
port->base.func = &nv94_i2c_func;
port->state = 7;
port->addr = nv50_i2c_addr[info->drive];
if (info->share != DCB_I2C_UNUSED) {
port->ctrl = 0x00e500 + (info->share * 0x50);
port->data = 0x0000e001;
}
return 0;
}
static const struct nouveau_i2c_func
nv94_aux_func = {
.acquire = nv94_i2c_acquire,
.release = nv94_i2c_release,
.aux = nv94_aux,
};
int
nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 index,
struct nouveau_object **pobject)
{
struct dcb_i2c_entry *info = data;
struct nv50_i2c_port *port;
int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_aux_algo, &port);
*pobject = nv_object(port);
if (ret)
return ret;
port->base.func = &nv94_aux_func;
port->addr = info->drive;
if (info->share != DCB_I2C_UNUSED) {
port->ctrl = 0x00e500 + (info->drive * 0x50);
port->data = 0x00002002;
}
return 0;
}
static struct nouveau_oclass
nv94_i2c_sclass[] = {
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv94_i2c_port_ctor,
.dtor = _nouveau_i2c_port_dtor,
.init = nv50_i2c_port_init,
.fini = _nouveau_i2c_port_fini,
},
},
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv94_aux_port_ctor,
.dtor = _nouveau_i2c_port_dtor,
.init = _nouveau_i2c_port_init,
.fini = _nouveau_i2c_port_fini,
},
},
{}
};
static int
nv94_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_i2c_priv *priv;
int ret;
ret = nouveau_i2c_create(parent, engine, oclass, nv94_i2c_sclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
return 0;
}
struct nouveau_oclass
nv94_i2c_oclass = {
.handle = NV_SUBDEV(I2C, 0x94),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv94_i2c_ctor,
.dtor = _nouveau_i2c_dtor,
.init = _nouveau_i2c_init,
.fini = _nouveau_i2c_fini,
},
};
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
static int
nvd0_i2c_sense_scl(struct nouveau_i2c_port *base)
{
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv50_i2c_port *port = (void *)base;
return !!(nv_rd32(priv, port->addr) & 0x00000010);
}
static int
nvd0_i2c_sense_sda(struct nouveau_i2c_port *base)
{
struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
struct nv50_i2c_port *port = (void *)base;
return !!(nv_rd32(priv, port->addr) & 0x00000020);
}
static const struct nouveau_i2c_func
nvd0_i2c_func = {
.acquire = nv94_i2c_acquire,
.release = nv94_i2c_release,
.drive_scl = nv50_i2c_drive_scl,
.drive_sda = nv50_i2c_drive_sda,
.sense_scl = nvd0_i2c_sense_scl,
.sense_sda = nvd0_i2c_sense_sda,
};
static int
nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 index,
struct nouveau_object **pobject)
{
struct dcb_i2c_entry *info = data;
struct nv50_i2c_port *port;
int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_bit_algo, &port);
*pobject = nv_object(port);
if (ret)
return ret;
port->base.func = &nvd0_i2c_func;
port->state = 0x00000007;
port->addr = 0x00d014 + (info->drive * 0x20);
if (info->share != DCB_I2C_UNUSED) {
port->ctrl = 0x00e500 + (info->share * 0x50);
port->data = 0x0000e001;
}
return 0;
}
static struct nouveau_oclass
nvd0_i2c_sclass[] = {
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvd0_i2c_port_ctor,
.dtor = _nouveau_i2c_port_dtor,
.init = nv50_i2c_port_init,
.fini = _nouveau_i2c_port_fini,
},
},
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv94_aux_port_ctor,
.dtor = _nouveau_i2c_port_dtor,
.init = _nouveau_i2c_port_init,
.fini = _nouveau_i2c_port_fini,
},
},
{}
};
static int
nvd0_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_i2c_priv *priv;
int ret;
ret = nouveau_i2c_create(parent, engine, oclass, nvd0_i2c_sclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
return 0;
}
struct nouveau_oclass
nvd0_i2c_oclass = {
.handle = NV_SUBDEV(I2C, 0xd0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvd0_i2c_ctor,
.dtor = _nouveau_i2c_dtor,
.init = _nouveau_i2c_init,
.fini = _nouveau_i2c_fini,
},
};
......@@ -31,7 +31,7 @@ static bool
probe_monitoring_device(struct nouveau_i2c_port *i2c,
struct i2c_board_info *info)
{
struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c->i2c);
struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c);
struct i2c_client *client;
request_module("%s%s", I2C_MODULE_PREFIX, info->type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment