mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 20:53:53 +08:00
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 <chris.brandt@renesas.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
9b09342f5c
commit
d982d66514
@ -84,12 +84,7 @@
|
|||||||
|
|
||||||
#define ICSR2_NACKF 0x10
|
#define ICSR2_NACKF 0x10
|
||||||
|
|
||||||
/* ICBRx (@ PCLK 33MHz) */
|
|
||||||
#define ICBR_RESERVED 0xe0 /* Should be 1 on writes */
|
#define ICBR_RESERVED 0xe0 /* Should be 1 on writes */
|
||||||
#define ICBRL_SP100K (19 | ICBR_RESERVED)
|
|
||||||
#define ICBRH_SP100K (16 | ICBR_RESERVED)
|
|
||||||
#define ICBRL_SP400K (21 | ICBR_RESERVED)
|
|
||||||
#define ICBRH_SP400K (9 | ICBR_RESERVED)
|
|
||||||
|
|
||||||
#define RIIC_INIT_MSG -1
|
#define RIIC_INIT_MSG -1
|
||||||
|
|
||||||
@ -288,48 +283,99 @@ static const struct i2c_algorithm riic_algo = {
|
|||||||
.functionality = riic_func,
|
.functionality = riic_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int riic_init_hw(struct riic_dev *riic, u32 spd)
|
static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
|
int total_ticks, cks, brl, brh;
|
||||||
|
|
||||||
ret = clk_prepare_enable(riic->clk);
|
ret = clk_prepare_enable(riic->clk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/*
|
if (t->bus_freq_hz > 400000) {
|
||||||
* TODO: Implement formula to calculate the timing values depending on
|
|
||||||
* variable parent clock rate and arbitrary bus speed
|
|
||||||
*/
|
|
||||||
rate = clk_get_rate(riic->clk);
|
|
||||||
if (rate != 33325000) {
|
|
||||||
dev_err(&riic->adapter.dev,
|
dev_err(&riic->adapter.dev,
|
||||||
"invalid parent clk (%lu). Must be 33325000Hz\n", rate);
|
"unsupported bus speed (%dHz). 400000 max\n",
|
||||||
|
t->bus_freq_hz);
|
||||||
clk_disable_unprepare(riic->clk);
|
clk_disable_unprepare(riic->clk);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rate = clk_get_rate(riic->clk);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assume the default register settings:
|
||||||
|
* FER.SCLE = 1 (SCL sync circuit enabled, adds 2 or 3 cycles)
|
||||||
|
* FER.NFE = 1 (noise circuit enabled)
|
||||||
|
* MR3.NF = 0 (1 cycle of noise filtered out)
|
||||||
|
*
|
||||||
|
* Freq (CKS=000) = (I2CCLK + tr + tf)/ (BRH + 3 + 1) + (BRL + 3 + 1)
|
||||||
|
* Freq (CKS!=000) = (I2CCLK + tr + tf)/ (BRH + 2 + 1) + (BRL + 2 + 1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine reference clock rate. We must be able to get the desired
|
||||||
|
* frequency with only 62 clock ticks max (31 high, 31 low).
|
||||||
|
* Aim for a duty of 60% LOW, 40% HIGH.
|
||||||
|
*/
|
||||||
|
total_ticks = DIV_ROUND_UP(rate, t->bus_freq_hz);
|
||||||
|
|
||||||
|
for (cks = 0; cks < 7; cks++) {
|
||||||
|
/*
|
||||||
|
* 60% low time must be less than BRL + 2 + 1
|
||||||
|
* BRL max register value is 0x1F.
|
||||||
|
*/
|
||||||
|
brl = ((total_ticks * 6) / 10);
|
||||||
|
if (brl <= (0x1F + 3))
|
||||||
|
break;
|
||||||
|
|
||||||
|
total_ticks /= 2;
|
||||||
|
rate /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (brl > (0x1F + 3)) {
|
||||||
|
dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n",
|
||||||
|
(unsigned long)t->bus_freq_hz);
|
||||||
|
clk_disable_unprepare(riic->clk);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
brh = total_ticks - brl;
|
||||||
|
|
||||||
|
/* Remove automatic clock ticks for sync circuit and NF */
|
||||||
|
if (cks == 0) {
|
||||||
|
brl -= 4;
|
||||||
|
brh -= 4;
|
||||||
|
} else {
|
||||||
|
brl -= 3;
|
||||||
|
brh -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove clock ticks for rise and fall times. Convert ns to clock
|
||||||
|
* ticks.
|
||||||
|
*/
|
||||||
|
brl -= t->scl_fall_ns / (1000000000 / rate);
|
||||||
|
brh -= t->scl_rise_ns / (1000000000 / rate);
|
||||||
|
|
||||||
|
/* Adjust for min register values for when SCLE=1 and NFE=1 */
|
||||||
|
if (brl < 1)
|
||||||
|
brl = 1;
|
||||||
|
if (brh < 1)
|
||||||
|
brh = 1;
|
||||||
|
|
||||||
|
pr_debug("i2c-riic: freq=%lu, duty=%d, fall=%lu, rise=%lu, cks=%d, brl=%d, brh=%d\n",
|
||||||
|
rate / total_ticks, ((brl + 3) * 100) / (brl + brh + 6),
|
||||||
|
t->scl_fall_ns / (1000000000 / rate),
|
||||||
|
t->scl_rise_ns / (1000000000 / rate), cks, brl, brh);
|
||||||
|
|
||||||
/* Changing the order of accessing IICRST and ICE may break things! */
|
/* Changing the order of accessing IICRST and ICE may break things! */
|
||||||
writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1);
|
writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1);
|
||||||
riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1);
|
riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1);
|
||||||
|
|
||||||
switch (spd) {
|
writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1);
|
||||||
case 100000:
|
writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH);
|
||||||
writeb(ICMR1_CKS(3), riic->base + RIIC_ICMR1);
|
writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL);
|
||||||
writeb(ICBRH_SP100K, riic->base + RIIC_ICBRH);
|
|
||||||
writeb(ICBRL_SP100K, riic->base + RIIC_ICBRL);
|
|
||||||
break;
|
|
||||||
case 400000:
|
|
||||||
writeb(ICMR1_CKS(1), riic->base + RIIC_ICMR1);
|
|
||||||
writeb(ICBRH_SP400K, riic->base + RIIC_ICBRH);
|
|
||||||
writeb(ICBRL_SP400K, riic->base + RIIC_ICBRL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dev_err(&riic->adapter.dev,
|
|
||||||
"unsupported bus speed (%dHz). Use 100000 or 400000\n", spd);
|
|
||||||
clk_disable_unprepare(riic->clk);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeb(0, riic->base + RIIC_ICSER);
|
writeb(0, riic->base + RIIC_ICSER);
|
||||||
writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3);
|
writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3);
|
||||||
@ -351,11 +397,10 @@ static struct riic_irq_desc riic_irqs[] = {
|
|||||||
|
|
||||||
static int riic_i2c_probe(struct platform_device *pdev)
|
static int riic_i2c_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
|
||||||
struct riic_dev *riic;
|
struct riic_dev *riic;
|
||||||
struct i2c_adapter *adap;
|
struct i2c_adapter *adap;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
u32 bus_rate = 0;
|
struct i2c_timings i2c_t;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL);
|
riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL);
|
||||||
@ -396,8 +441,9 @@ static int riic_i2c_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
init_completion(&riic->msg_done);
|
init_completion(&riic->msg_done);
|
||||||
|
|
||||||
of_property_read_u32(np, "clock-frequency", &bus_rate);
|
i2c_parse_fw_timings(&pdev->dev, &i2c_t, true);
|
||||||
ret = riic_init_hw(riic, bus_rate);
|
|
||||||
|
ret = riic_init_hw(riic, &i2c_t);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -408,7 +454,8 @@ static int riic_i2c_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
platform_set_drvdata(pdev, riic);
|
platform_set_drvdata(pdev, riic);
|
||||||
|
|
||||||
dev_info(&pdev->dev, "registered with %dHz bus speed\n", bus_rate);
|
dev_info(&pdev->dev, "registered with %dHz bus speed\n",
|
||||||
|
i2c_t.bus_freq_hz);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user