aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/vc.c
diff options
context:
space:
mode:
authorTero Kristo <t-kristo@ti.com>2012-09-25 12:33:48 -0400
committerKevin Hilman <khilman@ti.com>2012-11-05 18:31:12 -0500
commit00bd228ea9f7aad23f7933fa62a13d975d4b213a (patch)
treeaf86b29ef673efbc1e746bb279260482a6853ec7 /arch/arm/mach-omap2/vc.c
parent2ceec7b25c3cde53c68e49d64950f2ad1cab307d (diff)
ARM: OMAP4: VC: setup I2C parameters based on board data
VC code now provides a table of pre-calculated I2C setup parameters, which will be used based on the capacitance value calculated for the I2C trace on the PCB. A default trace length of 6.3cm is used unless board defines its own value during init. The parameters set will be the I2C internal pull setup and the I2C timing parameters for high speed use mode. Full speed mode is not supported as of now. Signed-off-by: Tero Kristo <t-kristo@ti.com> Signed-off-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/vc.c')
-rw-r--r--arch/arm/mach-omap2/vc.c149
1 files changed, 141 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index d72b787a0d83..687aa86c0d5e 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -24,6 +24,7 @@
24#include "prm44xx.h" 24#include "prm44xx.h"
25#include "pm.h" 25#include "pm.h"
26#include "scrm44xx.h" 26#include "scrm44xx.h"
27#include "control.h"
27 28
28/** 29/**
29 * struct omap_vc_channel_cfg - describe the cfg_channel bitfield 30 * struct omap_vc_channel_cfg - describe the cfg_channel bitfield
@@ -69,6 +70,9 @@ static struct omap_vc_channel_cfg vc_mutant_channel_cfg = {
69}; 70};
70 71
71static struct omap_vc_channel_cfg *vc_cfg_bits; 72static struct omap_vc_channel_cfg *vc_cfg_bits;
73
74/* Default I2C trace length on pcb, 6.3cm. Used for capacitance calculations. */
75static u32 sr_i2c_pcb_length = 63;
72#define CFG_CHANNEL_MASK 0x1f 76#define CFG_CHANNEL_MASK 0x1f
73 77
74/** 78/**
@@ -464,22 +468,135 @@ static void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode)
464/* OMAP4 specific voltage init functions */ 468/* OMAP4 specific voltage init functions */
465static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) 469static void __init omap4_vc_init_channel(struct voltagedomain *voltdm)
466{ 470{
467 static bool is_initialized;
468 u32 vc_val;
469
470 omap4_set_timings(voltdm, true); 471 omap4_set_timings(voltdm, true);
471 omap4_set_timings(voltdm, false); 472 omap4_set_timings(voltdm, false);
473}
474
475struct i2c_init_data {
476 u8 loadbits;
477 u8 load;
478 u8 hsscll_38_4;
479 u8 hsscll_26;
480 u8 hsscll_19_2;
481 u8 hsscll_16_8;
482 u8 hsscll_12;
483};
484
485static const __initdata struct i2c_init_data omap4_i2c_timing_data[] = {
486 {
487 .load = 50,
488 .loadbits = 0x3,
489 .hsscll_38_4 = 13,
490 .hsscll_26 = 11,
491 .hsscll_19_2 = 9,
492 .hsscll_16_8 = 9,
493 .hsscll_12 = 8,
494 },
495 {
496 .load = 25,
497 .loadbits = 0x2,
498 .hsscll_38_4 = 13,
499 .hsscll_26 = 11,
500 .hsscll_19_2 = 9,
501 .hsscll_16_8 = 9,
502 .hsscll_12 = 8,
503 },
504 {
505 .load = 12,
506 .loadbits = 0x1,
507 .hsscll_38_4 = 11,
508 .hsscll_26 = 10,
509 .hsscll_19_2 = 9,
510 .hsscll_16_8 = 9,
511 .hsscll_12 = 8,
512 },
513 {
514 .load = 0,
515 .loadbits = 0x0,
516 .hsscll_38_4 = 12,
517 .hsscll_26 = 10,
518 .hsscll_19_2 = 9,
519 .hsscll_16_8 = 8,
520 .hsscll_12 = 8,
521 },
522};
523
524/**
525 * omap4_vc_i2c_timing_init - sets up board I2C timing parameters
526 * @voltdm: voltagedomain pointer to get data from
527 *
528 * Use PMIC + board supplied settings for calculating the total I2C
529 * channel capacitance and set the timing parameters based on this.
530 * Pre-calculated values are provided in data tables, as it is not
531 * too straightforward to calculate these runtime.
532 */
533static void __init omap4_vc_i2c_timing_init(struct voltagedomain *voltdm)
534{
535 u32 capacitance;
536 u32 val;
537 u16 hsscll;
538 const struct i2c_init_data *i2c_data;
539
540 if (!voltdm->pmic->i2c_high_speed) {
541 pr_warn("%s: only high speed supported!\n", __func__);
542 return;
543 }
472 544
473 if (is_initialized) 545 /* PCB trace capacitance, 0.125pF / mm => mm / 8 */
546 capacitance = DIV_ROUND_UP(sr_i2c_pcb_length, 8);
547
548 /* OMAP pad capacitance */
549 capacitance += 4;
550
551 /* PMIC pad capacitance */
552 capacitance += voltdm->pmic->i2c_pad_load;
553
554 /* Search for capacitance match in the table */
555 i2c_data = omap4_i2c_timing_data;
556
557 while (i2c_data->load > capacitance)
558 i2c_data++;
559
560 /* Select proper values based on sysclk frequency */
561 switch (voltdm->sys_clk.rate) {
562 case 38400000:
563 hsscll = i2c_data->hsscll_38_4;
564 break;
565 case 26000000:
566 hsscll = i2c_data->hsscll_26;
567 break;
568 case 19200000:
569 hsscll = i2c_data->hsscll_19_2;
570 break;
571 case 16800000:
572 hsscll = i2c_data->hsscll_16_8;
573 break;
574 case 12000000:
575 hsscll = i2c_data->hsscll_12;
576 break;
577 default:
578 pr_warn("%s: unsupported sysclk rate: %d!\n", __func__,
579 voltdm->sys_clk.rate);
474 return; 580 return;
581 }
582
583 /* Loadbits define pull setup for the I2C channels */
584 val = i2c_data->loadbits << 25 | i2c_data->loadbits << 29;
475 585
476 /* XXX These are magic numbers and do not belong! */ 586 /* Write to SYSCTRL_PADCONF_WKUP_CTRL_I2C_2 to setup I2C pull */
477 vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT); 587 __raw_writel(val, OMAP2_L4_IO_ADDRESS(OMAP4_CTRL_MODULE_PAD_WKUP +
478 voltdm->write(vc_val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); 588 OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2));
479 589
480 is_initialized = true; 590 /* HSSCLH can always be zero */
591 val = hsscll << OMAP4430_HSSCLL_SHIFT;
592 val |= (0x28 << OMAP4430_SCLL_SHIFT | 0x2c << OMAP4430_SCLH_SHIFT);
593
594 /* Write setup times to I2C config register */
595 voltdm->write(val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET);
481} 596}
482 597
598
599
483/** 600/**
484 * omap_vc_i2c_init - initialize I2C interface to PMIC 601 * omap_vc_i2c_init - initialize I2C interface to PMIC
485 * @voltdm: voltage domain containing VC data 602 * @voltdm: voltage domain containing VC data
@@ -519,6 +636,9 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm)
519 mcode << __ffs(vc->common->i2c_mcode_mask), 636 mcode << __ffs(vc->common->i2c_mcode_mask),
520 vc->common->i2c_cfg_reg); 637 vc->common->i2c_cfg_reg);
521 638
639 if (cpu_is_omap44xx())
640 omap4_vc_i2c_timing_init(voltdm);
641
522 initialized = true; 642 initialized = true;
523} 643}
524 644
@@ -546,6 +666,19 @@ static u8 omap_vc_calc_vsel(struct voltagedomain *voltdm, u32 uvolt)
546 return voltdm->pmic->uv_to_vsel(uvolt); 666 return voltdm->pmic->uv_to_vsel(uvolt);
547} 667}
548 668
669/**
670 * omap_pm_setup_sr_i2c_pcb_length - set length of SR I2C traces on PCB
671 * @mm: length of the PCB trace in millimetres
672 *
673 * Sets the PCB trace length for the I2C channel. By default uses 63mm.
674 * This is needed for properly calculating the capacitance value for
675 * the PCB trace, and for setting the SR I2C channel timing parameters.
676 */
677void __init omap_pm_setup_sr_i2c_pcb_length(u32 mm)
678{
679 sr_i2c_pcb_length = mm;
680}
681
549void __init omap_vc_init_channel(struct voltagedomain *voltdm) 682void __init omap_vc_init_channel(struct voltagedomain *voltdm)
550{ 683{
551 struct omap_vc_channel *vc = voltdm->vc; 684 struct omap_vc_channel *vc = voltdm->vc;