1*868736adSOlli Salonen /* 2*868736adSOlli Salonen * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver 3*868736adSOlli Salonen * 4*868736adSOlli Salonen * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi> 5*868736adSOlli Salonen * 6*868736adSOlli Salonen * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual 7*868736adSOlli Salonen * DVB-S2 CI card (cimax2) with following copyrights: 8*868736adSOlli Salonen * 9*868736adSOlli Salonen * Copyright (C) 2009 NetUP Inc. 10*868736adSOlli Salonen * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> 11*868736adSOlli Salonen * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> 12*868736adSOlli Salonen * 13*868736adSOlli Salonen * This program is free software; you can redistribute it and/or modify 14*868736adSOlli Salonen * it under the terms of the GNU General Public License as published by 15*868736adSOlli Salonen * the Free Software Foundation; either version 2 of the License, or 16*868736adSOlli Salonen * (at your option) any later version. 17*868736adSOlli Salonen * 18*868736adSOlli Salonen * This program is distributed in the hope that it will be useful, 19*868736adSOlli Salonen * but WITHOUT ANY WARRANTY; without even the implied warranty of 20*868736adSOlli Salonen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21*868736adSOlli Salonen * GNU General Public License for more details. 22*868736adSOlli Salonen */ 23*868736adSOlli Salonen 24*868736adSOlli Salonen #include "sp2_priv.h" 25*868736adSOlli Salonen 26*868736adSOlli Salonen static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len) 27*868736adSOlli Salonen { 28*868736adSOlli Salonen int ret; 29*868736adSOlli Salonen struct i2c_client *client = s->client; 30*868736adSOlli Salonen struct i2c_adapter *adap = client->adapter; 31*868736adSOlli Salonen struct i2c_msg msg[] = { 32*868736adSOlli Salonen { 33*868736adSOlli Salonen .addr = client->addr, 34*868736adSOlli Salonen .flags = 0, 35*868736adSOlli Salonen .buf = ®, 36*868736adSOlli Salonen .len = 1 37*868736adSOlli Salonen }, { 38*868736adSOlli Salonen .addr = client->addr, 39*868736adSOlli Salonen .flags = I2C_M_RD, 40*868736adSOlli Salonen .buf = buf, 41*868736adSOlli Salonen .len = len 42*868736adSOlli Salonen } 43*868736adSOlli Salonen }; 44*868736adSOlli Salonen 45*868736adSOlli Salonen ret = i2c_transfer(adap, msg, 2); 46*868736adSOlli Salonen 47*868736adSOlli Salonen if (ret != 2) { 48*868736adSOlli Salonen dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n", 49*868736adSOlli Salonen reg, ret); 50*868736adSOlli Salonen if (ret < 0) 51*868736adSOlli Salonen return ret; 52*868736adSOlli Salonen else 53*868736adSOlli Salonen return -EIO; 54*868736adSOlli Salonen } 55*868736adSOlli Salonen 56*868736adSOlli Salonen dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n", 57*868736adSOlli Salonen client->addr, reg, buf[0]); 58*868736adSOlli Salonen 59*868736adSOlli Salonen return 0; 60*868736adSOlli Salonen } 61*868736adSOlli Salonen 62*868736adSOlli Salonen static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len) 63*868736adSOlli Salonen { 64*868736adSOlli Salonen int ret; 65*868736adSOlli Salonen u8 buffer[35]; 66*868736adSOlli Salonen struct i2c_client *client = s->client; 67*868736adSOlli Salonen struct i2c_adapter *adap = client->adapter; 68*868736adSOlli Salonen struct i2c_msg msg = { 69*868736adSOlli Salonen .addr = client->addr, 70*868736adSOlli Salonen .flags = 0, 71*868736adSOlli Salonen .buf = &buffer[0], 72*868736adSOlli Salonen .len = len + 1 73*868736adSOlli Salonen }; 74*868736adSOlli Salonen 75*868736adSOlli Salonen if ((len + 1) > sizeof(buffer)) { 76*868736adSOlli Salonen dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n", 77*868736adSOlli Salonen reg, len); 78*868736adSOlli Salonen return -EINVAL; 79*868736adSOlli Salonen } 80*868736adSOlli Salonen 81*868736adSOlli Salonen buffer[0] = reg; 82*868736adSOlli Salonen memcpy(&buffer[1], buf, len); 83*868736adSOlli Salonen 84*868736adSOlli Salonen ret = i2c_transfer(adap, &msg, 1); 85*868736adSOlli Salonen 86*868736adSOlli Salonen if (ret != 1) { 87*868736adSOlli Salonen dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n", 88*868736adSOlli Salonen reg, ret); 89*868736adSOlli Salonen if (ret < 0) 90*868736adSOlli Salonen return ret; 91*868736adSOlli Salonen else 92*868736adSOlli Salonen return -EIO; 93*868736adSOlli Salonen } 94*868736adSOlli Salonen 95*868736adSOlli Salonen return 0; 96*868736adSOlli Salonen } 97*868736adSOlli Salonen 98*868736adSOlli Salonen static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs, 99*868736adSOlli Salonen u8 read, int addr, u8 data) 100*868736adSOlli Salonen { 101*868736adSOlli Salonen struct sp2 *s = en50221->data; 102*868736adSOlli Salonen u8 store; 103*868736adSOlli Salonen int mem, ret; 104*868736adSOlli Salonen int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control; 105*868736adSOlli Salonen 106*868736adSOlli Salonen dev_dbg(&s->client->dev, "slot=%d, acs=0x%02x, addr=0x%04x, data = 0x%02x", 107*868736adSOlli Salonen slot, acs, addr, data); 108*868736adSOlli Salonen 109*868736adSOlli Salonen if (slot != 0) 110*868736adSOlli Salonen return -EINVAL; 111*868736adSOlli Salonen 112*868736adSOlli Salonen /* 113*868736adSOlli Salonen * change module access type between IO space and attribute memory 114*868736adSOlli Salonen * when needed 115*868736adSOlli Salonen */ 116*868736adSOlli Salonen if (s->module_access_type != acs) { 117*868736adSOlli Salonen ret = sp2_read_i2c(s, 0x00, &store, 1); 118*868736adSOlli Salonen 119*868736adSOlli Salonen if (ret) 120*868736adSOlli Salonen return ret; 121*868736adSOlli Salonen 122*868736adSOlli Salonen store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0); 123*868736adSOlli Salonen store |= acs; 124*868736adSOlli Salonen 125*868736adSOlli Salonen ret = sp2_write_i2c(s, 0x00, &store, 1); 126*868736adSOlli Salonen if (ret) 127*868736adSOlli Salonen return ret; 128*868736adSOlli Salonen } 129*868736adSOlli Salonen 130*868736adSOlli Salonen s->module_access_type = acs; 131*868736adSOlli Salonen 132*868736adSOlli Salonen /* implementation of ci_op_cam is device specific */ 133*868736adSOlli Salonen if (ci_op_cam) { 134*868736adSOlli Salonen ret = ci_op_cam(s->priv, read, addr, data, &mem); 135*868736adSOlli Salonen } else { 136*868736adSOlli Salonen dev_err(&s->client->dev, "callback not defined"); 137*868736adSOlli Salonen return -EINVAL; 138*868736adSOlli Salonen } 139*868736adSOlli Salonen 140*868736adSOlli Salonen if (ret) 141*868736adSOlli Salonen return ret; 142*868736adSOlli Salonen 143*868736adSOlli Salonen if (read) { 144*868736adSOlli Salonen dev_dbg(&s->client->dev, "cam read, addr=0x%04x, data = 0x%04x", 145*868736adSOlli Salonen addr, mem); 146*868736adSOlli Salonen return mem; 147*868736adSOlli Salonen } else { 148*868736adSOlli Salonen return 0; 149*868736adSOlli Salonen } 150*868736adSOlli Salonen } 151*868736adSOlli Salonen 152*868736adSOlli Salonen int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, 153*868736adSOlli Salonen int slot, int addr) 154*868736adSOlli Salonen { 155*868736adSOlli Salonen return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS, 156*868736adSOlli Salonen SP2_CI_RD, addr, 0); 157*868736adSOlli Salonen } 158*868736adSOlli Salonen 159*868736adSOlli Salonen int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, 160*868736adSOlli Salonen int slot, int addr, u8 data) 161*868736adSOlli Salonen { 162*868736adSOlli Salonen return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS, 163*868736adSOlli Salonen SP2_CI_WR, addr, data); 164*868736adSOlli Salonen } 165*868736adSOlli Salonen 166*868736adSOlli Salonen int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221, 167*868736adSOlli Salonen int slot, u8 addr) 168*868736adSOlli Salonen { 169*868736adSOlli Salonen return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS, 170*868736adSOlli Salonen SP2_CI_RD, addr, 0); 171*868736adSOlli Salonen } 172*868736adSOlli Salonen 173*868736adSOlli Salonen int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221, 174*868736adSOlli Salonen int slot, u8 addr, u8 data) 175*868736adSOlli Salonen { 176*868736adSOlli Salonen return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS, 177*868736adSOlli Salonen SP2_CI_WR, addr, data); 178*868736adSOlli Salonen } 179*868736adSOlli Salonen 180*868736adSOlli Salonen int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) 181*868736adSOlli Salonen { 182*868736adSOlli Salonen struct sp2 *s = en50221->data; 183*868736adSOlli Salonen u8 buf; 184*868736adSOlli Salonen int ret; 185*868736adSOlli Salonen 186*868736adSOlli Salonen dev_dbg(&s->client->dev, "slot: %d\n", slot); 187*868736adSOlli Salonen 188*868736adSOlli Salonen if (slot != 0) 189*868736adSOlli Salonen return -EINVAL; 190*868736adSOlli Salonen 191*868736adSOlli Salonen /* RST on */ 192*868736adSOlli Salonen buf = SP2_MOD_CTL_RST; 193*868736adSOlli Salonen ret = sp2_write_i2c(s, 0x00, &buf, 1); 194*868736adSOlli Salonen 195*868736adSOlli Salonen if (ret) 196*868736adSOlli Salonen return ret; 197*868736adSOlli Salonen 198*868736adSOlli Salonen usleep_range(500, 600); 199*868736adSOlli Salonen 200*868736adSOlli Salonen /* RST off */ 201*868736adSOlli Salonen buf = 0x00; 202*868736adSOlli Salonen ret = sp2_write_i2c(s, 0x00, &buf, 1); 203*868736adSOlli Salonen 204*868736adSOlli Salonen if (ret) 205*868736adSOlli Salonen return ret; 206*868736adSOlli Salonen 207*868736adSOlli Salonen msleep(1000); 208*868736adSOlli Salonen 209*868736adSOlli Salonen return 0; 210*868736adSOlli Salonen } 211*868736adSOlli Salonen 212*868736adSOlli Salonen int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) 213*868736adSOlli Salonen { 214*868736adSOlli Salonen struct sp2 *s = en50221->data; 215*868736adSOlli Salonen 216*868736adSOlli Salonen dev_dbg(&s->client->dev, "slot:%d\n", slot); 217*868736adSOlli Salonen 218*868736adSOlli Salonen /* not implemented */ 219*868736adSOlli Salonen return 0; 220*868736adSOlli Salonen } 221*868736adSOlli Salonen 222*868736adSOlli Salonen int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot) 223*868736adSOlli Salonen { 224*868736adSOlli Salonen struct sp2 *s = en50221->data; 225*868736adSOlli Salonen u8 buf; 226*868736adSOlli Salonen 227*868736adSOlli Salonen dev_dbg(&s->client->dev, "slot:%d\n", slot); 228*868736adSOlli Salonen 229*868736adSOlli Salonen if (slot != 0) 230*868736adSOlli Salonen return -EINVAL; 231*868736adSOlli Salonen 232*868736adSOlli Salonen sp2_read_i2c(s, 0x00, &buf, 1); 233*868736adSOlli Salonen 234*868736adSOlli Salonen /* disable bypass and enable TS */ 235*868736adSOlli Salonen buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN); 236*868736adSOlli Salonen return sp2_write_i2c(s, 0, &buf, 1); 237*868736adSOlli Salonen } 238*868736adSOlli Salonen 239*868736adSOlli Salonen int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221, 240*868736adSOlli Salonen int slot, int open) 241*868736adSOlli Salonen { 242*868736adSOlli Salonen struct sp2 *s = en50221->data; 243*868736adSOlli Salonen u8 buf[2]; 244*868736adSOlli Salonen int ret; 245*868736adSOlli Salonen 246*868736adSOlli Salonen dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open); 247*868736adSOlli Salonen 248*868736adSOlli Salonen /* 249*868736adSOlli Salonen * CAM module INSERT/REMOVE processing. Slow operation because of i2c 250*868736adSOlli Salonen * transfers. Throttle read to one per sec. 251*868736adSOlli Salonen */ 252*868736adSOlli Salonen if (time_after(jiffies, s->next_status_checked_time)) { 253*868736adSOlli Salonen ret = sp2_read_i2c(s, 0x00, buf, 1); 254*868736adSOlli Salonen s->next_status_checked_time = jiffies + msecs_to_jiffies(1000); 255*868736adSOlli Salonen 256*868736adSOlli Salonen if (ret) 257*868736adSOlli Salonen return 0; 258*868736adSOlli Salonen 259*868736adSOlli Salonen if (buf[0] & SP2_MOD_CTL_DET) 260*868736adSOlli Salonen s->status = DVB_CA_EN50221_POLL_CAM_PRESENT | 261*868736adSOlli Salonen DVB_CA_EN50221_POLL_CAM_READY; 262*868736adSOlli Salonen else 263*868736adSOlli Salonen s->status = 0; 264*868736adSOlli Salonen } 265*868736adSOlli Salonen 266*868736adSOlli Salonen return s->status; 267*868736adSOlli Salonen } 268*868736adSOlli Salonen 269*868736adSOlli Salonen int sp2_init(struct sp2 *s) 270*868736adSOlli Salonen { 271*868736adSOlli Salonen int ret = 0; 272*868736adSOlli Salonen u8 buf; 273*868736adSOlli Salonen u8 cimax_init[34] = { 274*868736adSOlli Salonen 0x00, /* module A control*/ 275*868736adSOlli Salonen 0x00, /* auto select mask high A */ 276*868736adSOlli Salonen 0x00, /* auto select mask low A */ 277*868736adSOlli Salonen 0x00, /* auto select pattern high A */ 278*868736adSOlli Salonen 0x00, /* auto select pattern low A */ 279*868736adSOlli Salonen 0x44, /* memory access time A, 600 ns */ 280*868736adSOlli Salonen 0x00, /* invert input A */ 281*868736adSOlli Salonen 0x00, /* RFU */ 282*868736adSOlli Salonen 0x00, /* RFU */ 283*868736adSOlli Salonen 0x00, /* module B control*/ 284*868736adSOlli Salonen 0x00, /* auto select mask high B */ 285*868736adSOlli Salonen 0x00, /* auto select mask low B */ 286*868736adSOlli Salonen 0x00, /* auto select pattern high B */ 287*868736adSOlli Salonen 0x00, /* auto select pattern low B */ 288*868736adSOlli Salonen 0x44, /* memory access time B, 600 ns */ 289*868736adSOlli Salonen 0x00, /* invert input B */ 290*868736adSOlli Salonen 0x00, /* RFU */ 291*868736adSOlli Salonen 0x00, /* RFU */ 292*868736adSOlli Salonen 0x00, /* auto select mask high Ext */ 293*868736adSOlli Salonen 0x00, /* auto select mask low Ext */ 294*868736adSOlli Salonen 0x00, /* auto select pattern high Ext */ 295*868736adSOlli Salonen 0x00, /* auto select pattern low Ext */ 296*868736adSOlli Salonen 0x00, /* RFU */ 297*868736adSOlli Salonen 0x02, /* destination - module A */ 298*868736adSOlli Salonen 0x01, /* power control reg, VCC power on */ 299*868736adSOlli Salonen 0x00, /* RFU */ 300*868736adSOlli Salonen 0x00, /* int status read only */ 301*868736adSOlli Salonen 0x00, /* Interrupt Mask Register */ 302*868736adSOlli Salonen 0x05, /* EXTINT=active-high, INT=push-pull */ 303*868736adSOlli Salonen 0x00, /* USCG1 */ 304*868736adSOlli Salonen 0x04, /* ack active low */ 305*868736adSOlli Salonen 0x00, /* LOCK = 0 */ 306*868736adSOlli Salonen 0x22, /* unknown */ 307*868736adSOlli Salonen 0x00, /* synchronization? */ 308*868736adSOlli Salonen }; 309*868736adSOlli Salonen 310*868736adSOlli Salonen dev_dbg(&s->client->dev, "\n"); 311*868736adSOlli Salonen 312*868736adSOlli Salonen s->ca.owner = THIS_MODULE; 313*868736adSOlli Salonen s->ca.read_attribute_mem = sp2_ci_read_attribute_mem; 314*868736adSOlli Salonen s->ca.write_attribute_mem = sp2_ci_write_attribute_mem; 315*868736adSOlli Salonen s->ca.read_cam_control = sp2_ci_read_cam_control; 316*868736adSOlli Salonen s->ca.write_cam_control = sp2_ci_write_cam_control; 317*868736adSOlli Salonen s->ca.slot_reset = sp2_ci_slot_reset; 318*868736adSOlli Salonen s->ca.slot_shutdown = sp2_ci_slot_shutdown; 319*868736adSOlli Salonen s->ca.slot_ts_enable = sp2_ci_slot_ts_enable; 320*868736adSOlli Salonen s->ca.poll_slot_status = sp2_ci_poll_slot_status; 321*868736adSOlli Salonen s->ca.data = s; 322*868736adSOlli Salonen s->module_access_type = 0; 323*868736adSOlli Salonen 324*868736adSOlli Salonen /* initialize all regs */ 325*868736adSOlli Salonen ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34); 326*868736adSOlli Salonen if (ret) 327*868736adSOlli Salonen goto err; 328*868736adSOlli Salonen 329*868736adSOlli Salonen /* lock registers */ 330*868736adSOlli Salonen buf = 1; 331*868736adSOlli Salonen ret = sp2_write_i2c(s, 0x1f, &buf, 1); 332*868736adSOlli Salonen if (ret) 333*868736adSOlli Salonen goto err; 334*868736adSOlli Salonen 335*868736adSOlli Salonen /* power on slots */ 336*868736adSOlli Salonen ret = sp2_write_i2c(s, 0x18, &buf, 1); 337*868736adSOlli Salonen if (ret) 338*868736adSOlli Salonen goto err; 339*868736adSOlli Salonen 340*868736adSOlli Salonen ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1); 341*868736adSOlli Salonen if (ret) 342*868736adSOlli Salonen goto err; 343*868736adSOlli Salonen 344*868736adSOlli Salonen return 0; 345*868736adSOlli Salonen 346*868736adSOlli Salonen err: 347*868736adSOlli Salonen dev_dbg(&s->client->dev, "init failed=%d\n", ret); 348*868736adSOlli Salonen return ret; 349*868736adSOlli Salonen } 350*868736adSOlli Salonen 351*868736adSOlli Salonen int sp2_exit(struct i2c_client *client) 352*868736adSOlli Salonen { 353*868736adSOlli Salonen struct sp2 *s; 354*868736adSOlli Salonen 355*868736adSOlli Salonen dev_dbg(&client->dev, "\n"); 356*868736adSOlli Salonen 357*868736adSOlli Salonen if (client == NULL) 358*868736adSOlli Salonen return 0; 359*868736adSOlli Salonen 360*868736adSOlli Salonen s = i2c_get_clientdata(client); 361*868736adSOlli Salonen if (s == NULL) 362*868736adSOlli Salonen return 0; 363*868736adSOlli Salonen 364*868736adSOlli Salonen if (s->ca.data == NULL) 365*868736adSOlli Salonen return 0; 366*868736adSOlli Salonen 367*868736adSOlli Salonen dvb_ca_en50221_release(&s->ca); 368*868736adSOlli Salonen 369*868736adSOlli Salonen return 0; 370*868736adSOlli Salonen } 371*868736adSOlli Salonen 372*868736adSOlli Salonen static int sp2_probe(struct i2c_client *client, 373*868736adSOlli Salonen const struct i2c_device_id *id) 374*868736adSOlli Salonen { 375*868736adSOlli Salonen struct sp2_config *cfg = client->dev.platform_data; 376*868736adSOlli Salonen struct sp2 *s; 377*868736adSOlli Salonen int ret; 378*868736adSOlli Salonen 379*868736adSOlli Salonen dev_dbg(&client->dev, "\n"); 380*868736adSOlli Salonen 381*868736adSOlli Salonen s = kzalloc(sizeof(struct sp2), GFP_KERNEL); 382*868736adSOlli Salonen if (!s) { 383*868736adSOlli Salonen ret = -ENOMEM; 384*868736adSOlli Salonen dev_err(&client->dev, "kzalloc() failed\n"); 385*868736adSOlli Salonen goto err; 386*868736adSOlli Salonen } 387*868736adSOlli Salonen 388*868736adSOlli Salonen s->client = client; 389*868736adSOlli Salonen s->dvb_adap = cfg->dvb_adap; 390*868736adSOlli Salonen s->priv = cfg->priv; 391*868736adSOlli Salonen s->ci_control = cfg->ci_control; 392*868736adSOlli Salonen 393*868736adSOlli Salonen i2c_set_clientdata(client, s); 394*868736adSOlli Salonen 395*868736adSOlli Salonen ret = sp2_init(s); 396*868736adSOlli Salonen if (ret) 397*868736adSOlli Salonen goto err; 398*868736adSOlli Salonen 399*868736adSOlli Salonen dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n"); 400*868736adSOlli Salonen return 0; 401*868736adSOlli Salonen err: 402*868736adSOlli Salonen dev_dbg(&client->dev, "init failed=%d\n", ret); 403*868736adSOlli Salonen kfree(s); 404*868736adSOlli Salonen 405*868736adSOlli Salonen return ret; 406*868736adSOlli Salonen } 407*868736adSOlli Salonen 408*868736adSOlli Salonen static int sp2_remove(struct i2c_client *client) 409*868736adSOlli Salonen { 410*868736adSOlli Salonen struct si2157 *s = i2c_get_clientdata(client); 411*868736adSOlli Salonen 412*868736adSOlli Salonen dev_dbg(&client->dev, "\n"); 413*868736adSOlli Salonen 414*868736adSOlli Salonen sp2_exit(client); 415*868736adSOlli Salonen if (s != NULL) 416*868736adSOlli Salonen kfree(s); 417*868736adSOlli Salonen 418*868736adSOlli Salonen return 0; 419*868736adSOlli Salonen } 420*868736adSOlli Salonen 421*868736adSOlli Salonen static const struct i2c_device_id sp2_id[] = { 422*868736adSOlli Salonen {"sp2", 0}, 423*868736adSOlli Salonen {} 424*868736adSOlli Salonen }; 425*868736adSOlli Salonen MODULE_DEVICE_TABLE(i2c, sp2_id); 426*868736adSOlli Salonen 427*868736adSOlli Salonen static struct i2c_driver sp2_driver = { 428*868736adSOlli Salonen .driver = { 429*868736adSOlli Salonen .owner = THIS_MODULE, 430*868736adSOlli Salonen .name = "sp2", 431*868736adSOlli Salonen }, 432*868736adSOlli Salonen .probe = sp2_probe, 433*868736adSOlli Salonen .remove = sp2_remove, 434*868736adSOlli Salonen .id_table = sp2_id, 435*868736adSOlli Salonen }; 436*868736adSOlli Salonen 437*868736adSOlli Salonen module_i2c_driver(sp2_driver); 438*868736adSOlli Salonen 439*868736adSOlli Salonen MODULE_DESCRIPTION("CIMaX SP2/HF CI driver"); 440*868736adSOlli Salonen MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>"); 441*868736adSOlli Salonen MODULE_LICENSE("GPL"); 442