Skip to content

Commit d982d66

Browse files
seebeWolfram Sang
authored andcommitted
i2c: riic: remove clock and frequency restrictions
Remove the restriction that the parent clock has to be a specific frequency and also allow any speed to be supported. Signed-off-by: Chris Brandt <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 9b09342 commit d982d66

File tree

1 file changed

+81
-34
lines changed

1 file changed

+81
-34
lines changed

drivers/i2c/busses/i2c-riic.c

Lines changed: 81 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,7 @@
8484

8585
#define ICSR2_NACKF 0x10
8686

87-
/* ICBRx (@ PCLK 33MHz) */
8887
#define ICBR_RESERVED 0xe0 /* Should be 1 on writes */
89-
#define ICBRL_SP100K (19 | ICBR_RESERVED)
90-
#define ICBRH_SP100K (16 | ICBR_RESERVED)
91-
#define ICBRL_SP400K (21 | ICBR_RESERVED)
92-
#define ICBRH_SP400K (9 | ICBR_RESERVED)
9388

9489
#define RIIC_INIT_MSG -1
9590

@@ -288,48 +283,99 @@ static const struct i2c_algorithm riic_algo = {
288283
.functionality = riic_func,
289284
};
290285

291-
static int riic_init_hw(struct riic_dev *riic, u32 spd)
286+
static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
292287
{
293288
int ret;
294289
unsigned long rate;
290+
int total_ticks, cks, brl, brh;
295291

296292
ret = clk_prepare_enable(riic->clk);
297293
if (ret)
298294
return ret;
299295

296+
if (t->bus_freq_hz > 400000) {
297+
dev_err(&riic->adapter.dev,
298+
"unsupported bus speed (%dHz). 400000 max\n",
299+
t->bus_freq_hz);
300+
clk_disable_unprepare(riic->clk);
301+
return -EINVAL;
302+
}
303+
304+
rate = clk_get_rate(riic->clk);
305+
300306
/*
301-
* TODO: Implement formula to calculate the timing values depending on
302-
* variable parent clock rate and arbitrary bus speed
307+
* Assume the default register settings:
308+
* FER.SCLE = 1 (SCL sync circuit enabled, adds 2 or 3 cycles)
309+
* FER.NFE = 1 (noise circuit enabled)
310+
* MR3.NF = 0 (1 cycle of noise filtered out)
311+
*
312+
* Freq (CKS=000) = (I2CCLK + tr + tf)/ (BRH + 3 + 1) + (BRL + 3 + 1)
313+
* Freq (CKS!=000) = (I2CCLK + tr + tf)/ (BRH + 2 + 1) + (BRL + 2 + 1)
303314
*/
304-
rate = clk_get_rate(riic->clk);
305-
if (rate != 33325000) {
306-
dev_err(&riic->adapter.dev,
307-
"invalid parent clk (%lu). Must be 33325000Hz\n", rate);
315+
316+
/*
317+
* Determine reference clock rate. We must be able to get the desired
318+
* frequency with only 62 clock ticks max (31 high, 31 low).
319+
* Aim for a duty of 60% LOW, 40% HIGH.
320+
*/
321+
total_ticks = DIV_ROUND_UP(rate, t->bus_freq_hz);
322+
323+
for (cks = 0; cks < 7; cks++) {
324+
/*
325+
* 60% low time must be less than BRL + 2 + 1
326+
* BRL max register value is 0x1F.
327+
*/
328+
brl = ((total_ticks * 6) / 10);
329+
if (brl <= (0x1F + 3))
330+
break;
331+
332+
total_ticks /= 2;
333+
rate /= 2;
334+
}
335+
336+
if (brl > (0x1F + 3)) {
337+
dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n",
338+
(unsigned long)t->bus_freq_hz);
308339
clk_disable_unprepare(riic->clk);
309340
return -EINVAL;
310341
}
311342

343+
brh = total_ticks - brl;
344+
345+
/* Remove automatic clock ticks for sync circuit and NF */
346+
if (cks == 0) {
347+
brl -= 4;
348+
brh -= 4;
349+
} else {
350+
brl -= 3;
351+
brh -= 3;
352+
}
353+
354+
/*
355+
* Remove clock ticks for rise and fall times. Convert ns to clock
356+
* ticks.
357+
*/
358+
brl -= t->scl_fall_ns / (1000000000 / rate);
359+
brh -= t->scl_rise_ns / (1000000000 / rate);
360+
361+
/* Adjust for min register values for when SCLE=1 and NFE=1 */
362+
if (brl < 1)
363+
brl = 1;
364+
if (brh < 1)
365+
brh = 1;
366+
367+
pr_debug("i2c-riic: freq=%lu, duty=%d, fall=%lu, rise=%lu, cks=%d, brl=%d, brh=%d\n",
368+
rate / total_ticks, ((brl + 3) * 100) / (brl + brh + 6),
369+
t->scl_fall_ns / (1000000000 / rate),
370+
t->scl_rise_ns / (1000000000 / rate), cks, brl, brh);
371+
312372
/* Changing the order of accessing IICRST and ICE may break things! */
313373
writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1);
314374
riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1);
315375

316-
switch (spd) {
317-
case 100000:
318-
writeb(ICMR1_CKS(3), riic->base + RIIC_ICMR1);
319-
writeb(ICBRH_SP100K, riic->base + RIIC_ICBRH);
320-
writeb(ICBRL_SP100K, riic->base + RIIC_ICBRL);
321-
break;
322-
case 400000:
323-
writeb(ICMR1_CKS(1), riic->base + RIIC_ICMR1);
324-
writeb(ICBRH_SP400K, riic->base + RIIC_ICBRH);
325-
writeb(ICBRL_SP400K, riic->base + RIIC_ICBRL);
326-
break;
327-
default:
328-
dev_err(&riic->adapter.dev,
329-
"unsupported bus speed (%dHz). Use 100000 or 400000\n", spd);
330-
clk_disable_unprepare(riic->clk);
331-
return -EINVAL;
332-
}
376+
writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1);
377+
writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH);
378+
writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL);
333379

334380
writeb(0, riic->base + RIIC_ICSER);
335381
writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3);
@@ -351,11 +397,10 @@ static struct riic_irq_desc riic_irqs[] = {
351397

352398
static int riic_i2c_probe(struct platform_device *pdev)
353399
{
354-
struct device_node *np = pdev->dev.of_node;
355400
struct riic_dev *riic;
356401
struct i2c_adapter *adap;
357402
struct resource *res;
358-
u32 bus_rate = 0;
403+
struct i2c_timings i2c_t;
359404
int i, ret;
360405

361406
riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL);
@@ -396,8 +441,9 @@ static int riic_i2c_probe(struct platform_device *pdev)
396441

397442
init_completion(&riic->msg_done);
398443

399-
of_property_read_u32(np, "clock-frequency", &bus_rate);
400-
ret = riic_init_hw(riic, bus_rate);
444+
i2c_parse_fw_timings(&pdev->dev, &i2c_t, true);
445+
446+
ret = riic_init_hw(riic, &i2c_t);
401447
if (ret)
402448
return ret;
403449

@@ -408,7 +454,8 @@ static int riic_i2c_probe(struct platform_device *pdev)
408454

409455
platform_set_drvdata(pdev, riic);
410456

411-
dev_info(&pdev->dev, "registered with %dHz bus speed\n", bus_rate);
457+
dev_info(&pdev->dev, "registered with %dHz bus speed\n",
458+
i2c_t.bus_freq_hz);
412459
return 0;
413460
}
414461

0 commit comments

Comments
 (0)