Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
git-mirror
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
0
Pull requests
0
Actions
Projects
0
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security
Insights
Files
3c96888
Documentation
arch
block
certs
crypto
drivers
accessibility
acpi
amba
android
ata
atm
auxdisplay
base
bcma
block
bluetooth
bus
cdrom
char
clk
clocksource
connector
cpufreq
cpuidle
crypto
dca
devfreq
dio
dma-buf
dma
edac
eisa
extcon
firewire
firmware
fmc
fpga
gpio
gpu
hid
hsi
hv
hwmon
hwspinlock
hwtracing
i2c
ide
idle
iio
infiniband
input
iommu
ipack
irqchip
isdn
leds
lguest
lightnvm
macintosh
mailbox
mcb
md
media
common
dvb-core
dvb-frontends
drx39xyj
Kconfig
Makefile
a8293.c
a8293.h
af9013.c
af9013.h
af9013_priv.h
af9033.c
af9033.h
af9033_priv.h
as102_fe.c
as102_fe.h
as102_fe_types.h
ascot2e.c
ascot2e.h
atbm8830.c
atbm8830.h
atbm8830_priv.h
au8522.h
au8522_common.c
au8522_decoder.c
au8522_dig.c
au8522_priv.h
bcm3510.c
bcm3510.h
bcm3510_priv.h
bsbe1-d01a.h
bsbe1.h
bsru6.h
cx22700.c
cx22700.h
cx22702.c
cx22702.h
cx24110.c
cx24110.h
cx24113.c
cx24113.h
cx24116.c
cx24116.h
cx24117.c
cx24117.h
cx24120.c
cx24120.h
cx24123.c
cx24123.h
cxd2820r.h
cxd2820r_c.c
cxd2820r_core.c
cxd2820r_priv.h
cxd2820r_t.c
cxd2820r_t2.c
cxd2841er.c
cxd2841er.h
cxd2841er_priv.h
dib0070.c
dib0070.h
dib0090.c
dib0090.h
dib3000.h
dib3000mb.c
dib3000mb_priv.h
dib3000mc.c
dib3000mc.h
dib7000m.c
dib7000m.h
dib7000p.c
dib7000p.h
dib8000.c
dib8000.h
dib9000.c
dib9000.h
dibx000_common.c
dibx000_common.h
drxd.h
drxd_firm.c
drxd_firm.h
drxd_hard.c
drxd_map_firm.h
drxk.h
drxk_hard.c
drxk_hard.h
drxk_map.h
ds3000.c
ds3000.h
dvb-pll.c
dvb-pll.h
dvb_dummy_fe.c
dvb_dummy_fe.h
ec100.c
ec100.h
eds1547.h
hd29l2.c
hd29l2.h
hd29l2_priv.h
horus3a.c
horus3a.h
isl6405.c
isl6405.h
isl6421.c
isl6421.h
isl6423.c
isl6423.h
itd1000.c
itd1000.h
itd1000_priv.h
ix2505v.c
ix2505v.h
l64781.c
l64781.h
lg2160.c
lg2160.h
lgdt3305.c
lgdt3305.h
lgdt3306a.c
lgdt3306a.h
lgdt330x.c
lgdt330x.h
lgdt330x_priv.h
lgs8gl5.c
lgs8gl5.h
lgs8gxx.c
lgs8gxx.h
lgs8gxx_priv.h
lnbh24.h
lnbh25.c
lnbh25.h
lnbp21.c
lnbp21.h
lnbp22.c
lnbp22.h
m88ds3103.c
m88ds3103.h
m88ds3103_priv.h
m88rs2000.c
m88rs2000.h
mb86a16.c
mb86a16.h
mb86a16_priv.h
mb86a20s.c
mb86a20s.h
mn88472.h
mn88473.c
mn88473.h
mn88473_priv.h
mt312.c
mt312.h
mt312_priv.h
mt352.c
mt352.h
mt352_priv.h
nxt200x.c
nxt200x.h
nxt6000.c
nxt6000.h
nxt6000_priv.h
or51132.c
or51132.h
or51211.c
or51211.h
rtl2830.c
rtl2830.h
rtl2830_priv.h
rtl2832.c
rtl2832.h
rtl2832_priv.h
rtl2832_sdr.c
rtl2832_sdr.h
s5h1409.c
s5h1409.h
s5h1411.c
s5h1411.h
s5h1420.c
s5h1420.h
s5h1420_priv.h
s5h1432.c
s5h1432.h
s921.c
s921.h
si2165.c
si2165.h
si2165_priv.h
si2168.c
si2168.h
si2168_priv.h
si21xx.c
si21xx.h
sp2.c
sp2.h
sp2_priv.h
sp8870.c
sp8870.h
sp887x.c
sp887x.h
stb0899_algo.c
stb0899_cfg.h
stb0899_drv.c
stb0899_drv.h
stb0899_priv.h
stb0899_reg.h
stb6000.c
stb6000.h
stb6100.c
stb6100.h
stb6100_cfg.h
stb6100_proc.h
stv0288.c
stv0288.h
stv0297.c
stv0297.h
stv0299.c
stv0299.h
stv0367.c
stv0367.h
stv0367_priv.h
stv0367_regs.h
stv0900.h
stv0900_core.c
stv0900_init.h
stv0900_priv.h
stv0900_reg.h
stv0900_sw.c
stv090x.c
stv090x.h
stv090x_priv.h
stv090x_reg.h
stv6110.c
stv6110.h
stv6110x.c
stv6110x.h
stv6110x_priv.h
stv6110x_reg.h
tc90522.c
tc90522.h
tda10021.c
tda10023.c
tda1002x.h
tda10048.c
tda10048.h
tda1004x.c
tda1004x.h
tda10071.c
tda10071.h
tda10071_priv.h
tda10086.c
tda10086.h
tda18271c2dd.c
tda18271c2dd.h
tda18271c2dd_maps.h
tda665x.c
tda665x.h
tda8083.c
tda8083.h
tda8261.c
tda8261.h
tda8261_cfg.h
tda826x.c
tda826x.h
tdhd1.h
ts2020.c
ts2020.h
tua6100.c
tua6100.h
ves1820.c
ves1820.h
ves1x93.c
ves1x93.h
z0194a.h
zl10036.c
zl10036.h
zl10039.c
zl10039.h
zl10353.c
zl10353.h
zl10353_priv.h
firewire
i2c
mmc
pci
platform
radio
rc
tuners
usb
v4l2-core
Kconfig
Makefile
media-device.c
media-devnode.c
media-entity.c
memory
memstick
message
mfd
misc
mmc
mtd
net
nfc
ntb
nubus
nvdimm
nvme
nvmem
of
oprofile
parisc
parport
pci
pcmcia
perf
phy
pinctrl
platform
pnp
power
powercap
pps
ps3
ptp
pwm
rapidio
ras
regulator
remoteproc
reset
rpmsg
rtc
s390
sbus
scsi
sfi
sh
sn
soc
spi
spmi
ssb
staging
target
tc
thermal
thunderbolt
tty
uio
usb
uwb
vfio
vhost
video
virt
virtio
vlynq
vme
w1
watchdog
xen
zorro
Kconfig
Makefile
firmware
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
usr
virt
.get_maintainer.ignore
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
drivers
/
media
/
dvb-frontends
/
sp2.c
Blame
Blame
Latest commit
History
History
440 lines (357 loc) · 9.32 KB
Breadcrumbs
linux
/
drivers
/
media
/
dvb-frontends
/
sp2.c
Top
File metadata and controls
Code
Blame
440 lines (357 loc) · 9.32 KB
Raw
/* * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver * * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi> * * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual * DVB-S2 CI card (cimax2) with following copyrights: * * Copyright (C) 2009 NetUP Inc. * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "sp2_priv.h" static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len) { int ret; struct i2c_client *client = s->client; struct i2c_adapter *adap = client->adapter; struct i2c_msg msg[] = { { .addr = client->addr, .flags = 0, .buf = ®, .len = 1 }, { .addr = client->addr, .flags = I2C_M_RD, .buf = buf, .len = len } }; ret = i2c_transfer(adap, msg, 2); if (ret != 2) { dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n", reg, ret); if (ret < 0) return ret; else return -EIO; } dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n", client->addr, reg, buf[0]); return 0; } static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len) { int ret; u8 buffer[35]; struct i2c_client *client = s->client; struct i2c_adapter *adap = client->adapter; struct i2c_msg msg = { .addr = client->addr, .flags = 0, .buf = &buffer[0], .len = len + 1 }; if ((len + 1) > sizeof(buffer)) { dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n", reg, len); return -EINVAL; } buffer[0] = reg; memcpy(&buffer[1], buf, len); ret = i2c_transfer(adap, &msg, 1); if (ret != 1) { dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n", reg, ret); if (ret < 0) return ret; else return -EIO; } dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %*ph\n", client->addr, reg, len, buf); return 0; } static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs, u8 read, int addr, u8 data) { struct sp2 *s = en50221->data; u8 store; int mem, ret; int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control; if (slot != 0) return -EINVAL; /* * change module access type between IO space and attribute memory * when needed */ if (s->module_access_type != acs) { ret = sp2_read_i2c(s, 0x00, &store, 1); if (ret) return ret; store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0); store |= acs; ret = sp2_write_i2c(s, 0x00, &store, 1); if (ret) return ret; } s->module_access_type = acs; /* implementation of ci_op_cam is device specific */ if (ci_op_cam) { ret = ci_op_cam(s->priv, read, addr, data, &mem); } else { dev_err(&s->client->dev, "callback not defined"); return -EINVAL; } if (ret) return ret; dev_dbg(&s->client->dev, "%s: slot=%d, addr=0x%04x, %s, data=%x", (read) ? "read" : "write", slot, addr, (acs == SP2_CI_ATTR_ACS) ? "attr" : "io", (read) ? mem : data); if (read) return mem; else return 0; } int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, int slot, int addr) { return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS, SP2_CI_RD, addr, 0); } int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data) { return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS, SP2_CI_WR, addr, data); } int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221, int slot, u8 addr) { return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS, SP2_CI_RD, addr, 0); } int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data) { return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS, SP2_CI_WR, addr, data); } int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) { struct sp2 *s = en50221->data; u8 buf; int ret; dev_dbg(&s->client->dev, "slot: %d\n", slot); if (slot != 0) return -EINVAL; /* RST on */ buf = SP2_MOD_CTL_RST; ret = sp2_write_i2c(s, 0x00, &buf, 1); if (ret) return ret; usleep_range(500, 600); /* RST off */ buf = 0x00; ret = sp2_write_i2c(s, 0x00, &buf, 1); if (ret) return ret; msleep(1000); return 0; } int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) { struct sp2 *s = en50221->data; dev_dbg(&s->client->dev, "slot:%d\n", slot); /* not implemented */ return 0; } int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot) { struct sp2 *s = en50221->data; u8 buf; dev_dbg(&s->client->dev, "slot:%d\n", slot); if (slot != 0) return -EINVAL; sp2_read_i2c(s, 0x00, &buf, 1); /* disable bypass and enable TS */ buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN); return sp2_write_i2c(s, 0, &buf, 1); } int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) { struct sp2 *s = en50221->data; u8 buf[2]; int ret; dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open); /* * CAM module INSERT/REMOVE processing. Slow operation because of i2c * transfers. Throttle read to one per sec. */ if (time_after(jiffies, s->next_status_checked_time)) { ret = sp2_read_i2c(s, 0x00, buf, 1); s->next_status_checked_time = jiffies + msecs_to_jiffies(1000); if (ret) return 0; if (buf[0] & SP2_MOD_CTL_DET) s->status = DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; else s->status = 0; } return s->status; } static int sp2_init(struct sp2 *s) { int ret = 0; u8 buf; u8 cimax_init[34] = { 0x00, /* module A control*/ 0x00, /* auto select mask high A */ 0x00, /* auto select mask low A */ 0x00, /* auto select pattern high A */ 0x00, /* auto select pattern low A */ 0x44, /* memory access time A, 600 ns */ 0x00, /* invert input A */ 0x00, /* RFU */ 0x00, /* RFU */ 0x00, /* module B control*/ 0x00, /* auto select mask high B */ 0x00, /* auto select mask low B */ 0x00, /* auto select pattern high B */ 0x00, /* auto select pattern low B */ 0x44, /* memory access time B, 600 ns */ 0x00, /* invert input B */ 0x00, /* RFU */ 0x00, /* RFU */ 0x00, /* auto select mask high Ext */ 0x00, /* auto select mask low Ext */ 0x00, /* auto select pattern high Ext */ 0x00, /* auto select pattern low Ext */ 0x00, /* RFU */ 0x02, /* destination - module A */ 0x01, /* power control reg, VCC power on */ 0x00, /* RFU */ 0x00, /* int status read only */ 0x00, /* Interrupt Mask Register */ 0x05, /* EXTINT=active-high, INT=push-pull */ 0x00, /* USCG1 */ 0x04, /* ack active low */ 0x00, /* LOCK = 0 */ 0x22, /* unknown */ 0x00, /* synchronization? */ }; dev_dbg(&s->client->dev, "\n"); s->ca.owner = THIS_MODULE; s->ca.read_attribute_mem = sp2_ci_read_attribute_mem; s->ca.write_attribute_mem = sp2_ci_write_attribute_mem; s->ca.read_cam_control = sp2_ci_read_cam_control; s->ca.write_cam_control = sp2_ci_write_cam_control; s->ca.slot_reset = sp2_ci_slot_reset; s->ca.slot_shutdown = sp2_ci_slot_shutdown; s->ca.slot_ts_enable = sp2_ci_slot_ts_enable; s->ca.poll_slot_status = sp2_ci_poll_slot_status; s->ca.data = s; s->module_access_type = 0; /* initialize all regs */ ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34); if (ret) goto err; /* lock registers */ buf = 1; ret = sp2_write_i2c(s, 0x1f, &buf, 1); if (ret) goto err; /* power on slots */ ret = sp2_write_i2c(s, 0x18, &buf, 1); if (ret) goto err; ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1); if (ret) goto err; return 0; err: dev_dbg(&s->client->dev, "init failed=%d\n", ret); return ret; } static int sp2_exit(struct i2c_client *client) { struct sp2 *s; dev_dbg(&client->dev, "\n"); if (client == NULL) return 0; s = i2c_get_clientdata(client); if (s == NULL) return 0; if (s->ca.data == NULL) return 0; dvb_ca_en50221_release(&s->ca); return 0; } static int sp2_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct sp2_config *cfg = client->dev.platform_data; struct sp2 *s; int ret; dev_dbg(&client->dev, "\n"); s = kzalloc(sizeof(struct sp2), GFP_KERNEL); if (!s) { ret = -ENOMEM; dev_err(&client->dev, "kzalloc() failed\n"); goto err; } s->client = client; s->dvb_adap = cfg->dvb_adap; s->priv = cfg->priv; s->ci_control = cfg->ci_control; i2c_set_clientdata(client, s); ret = sp2_init(s); if (ret) goto err; dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n"); return 0; err: dev_dbg(&client->dev, "init failed=%d\n", ret); kfree(s); return ret; } static int sp2_remove(struct i2c_client *client) { struct sp2 *s = i2c_get_clientdata(client); dev_dbg(&client->dev, "\n"); sp2_exit(client); kfree(s); return 0; } static const struct i2c_device_id sp2_id[] = { {"sp2", 0}, {} }; MODULE_DEVICE_TABLE(i2c, sp2_id); static struct i2c_driver sp2_driver = { .driver = { .name = "sp2", }, .probe = sp2_probe, .remove = sp2_remove, .id_table = sp2_id, }; module_i2c_driver(sp2_driver); MODULE_DESCRIPTION("CIMaX SP2/HF CI driver"); MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>"); MODULE_LICENSE("GPL");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
You can’t perform that action at this time.