1 // SPDX-License-Identifier: GPL-2.0
3 * ddbridge-mci.c: Digital Devices microcode interface
5 * Copyright (C) 2017-2018 Digital Devices GmbH
6 * Ralph Metzler <rjkm@metzlerbros.de>
7 * Marcus Metzler <mocm@metzlerbros.de>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 only, as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
20 #include "ddbridge-io.h"
21 #include "ddbridge-mci.h"
23 static LIST_HEAD(mci_list
);
25 static int mci_reset(struct mci
*state
)
27 struct ddb_link
*link
= state
->base
->link
;
31 ddblwritel(link
, MCI_CONTROL_RESET
, MCI_CONTROL
);
32 ddblwritel(link
, 0, MCI_CONTROL
+ 4); /* 1= no internal init */
34 ddblwritel(link
, 0, MCI_CONTROL
);
37 status
= ddblreadl(link
, MCI_CONTROL
);
38 if ((status
& MCI_CONTROL_READY
) == MCI_CONTROL_READY
)
44 if ((status
& MCI_CONTROL_READY
) == 0)
46 if (link
->ids
.device
== 0x0009)
47 ddblwritel(link
, SX8_TSCONFIG_MODE_NORMAL
, SX8_TSCONFIG
);
51 int ddb_mci_config(struct mci
*state
, u32 config
)
53 struct ddb_link
*link
= state
->base
->link
;
55 if (link
->ids
.device
!= 0x0009)
57 ddblwritel(link
, config
, SX8_TSCONFIG
);
61 static int _mci_cmd_unlocked(struct mci
*state
,
62 u32
*cmd
, u32 cmd_len
,
63 u32
*res
, u32 res_len
)
65 struct ddb_link
*link
= state
->base
->link
;
69 val
= ddblreadl(link
, MCI_CONTROL
);
70 if (val
& (MCI_CONTROL_RESET
| MCI_CONTROL_START_COMMAND
))
73 for (i
= 0; i
< cmd_len
; i
++)
74 ddblwritel(link
, cmd
[i
], MCI_COMMAND
+ i
* 4);
75 val
|= (MCI_CONTROL_START_COMMAND
| MCI_CONTROL_ENABLE_DONE_INTERRUPT
);
76 ddblwritel(link
, val
, MCI_CONTROL
);
78 stat
= wait_for_completion_timeout(&state
->base
->completion
, HZ
);
80 dev_warn(state
->base
->dev
, "MCI-%d: MCI timeout\n", state
->nr
);
84 for (i
= 0; i
< res_len
; i
++)
85 res
[i
] = ddblreadl(link
, MCI_RESULT
+ i
* 4);
89 int ddb_mci_cmd(struct mci
*state
,
90 struct mci_command
*command
,
91 struct mci_result
*result
)
95 mutex_lock(&state
->base
->mci_lock
);
96 stat
= _mci_cmd_unlocked(state
,
97 (u32
*)command
, sizeof(*command
) / sizeof(u32
),
98 (u32
*)result
, sizeof(*result
) / sizeof(u32
));
99 mutex_unlock(&state
->base
->mci_lock
);
103 static void mci_handler(void *priv
)
105 struct mci_base
*base
= (struct mci_base
*)priv
;
107 complete(&base
->completion
);
110 static struct mci_base
*match_base(void *key
)
114 list_for_each_entry(p
, &mci_list
, mci_list
)
120 static int probe(struct mci
*state
)
127 *ddb_mci_attach(struct ddb_input
*input
, struct mci_cfg
*cfg
, int nr
,
128 int (**fn_set_input
)(struct dvb_frontend
*fe
, int input
))
130 struct ddb_port
*port
= input
->port
;
131 struct ddb
*dev
= port
->dev
;
132 struct ddb_link
*link
= &dev
->link
[port
->lnr
];
133 struct mci_base
*base
;
135 void *key
= cfg
->type
? (void *)port
: (void *)link
;
137 state
= kzalloc(cfg
->state_size
, GFP_KERNEL
);
141 base
= match_base(key
);
146 base
= kzalloc(cfg
->base_size
, GFP_KERNEL
);
152 base
->dev
= dev
->dev
;
153 mutex_init(&base
->mci_lock
);
154 mutex_init(&base
->tuner_lock
);
155 ddb_irq_set(dev
, link
->nr
, 0, mci_handler
, base
);
156 init_completion(&base
->completion
);
158 if (probe(state
) < 0) {
162 list_add(&base
->mci_list
, &mci_list
);
164 cfg
->base_init(base
);
166 memcpy(&state
->fe
.ops
, cfg
->fe_ops
, sizeof(struct dvb_frontend_ops
));
167 state
->fe
.demodulator_priv
= state
;
169 *fn_set_input
= cfg
->set_input
;