@@ -14,7 +14,6 @@
* published by the Free Software Foundation.
*/
-
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -33,6 +32,8 @@
#include <plat/clock.h>
#include <plat/opp.h>
#include <plat/opp_twl_tps.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
#include "prm.h"
#include "smartreflex.h"
@@ -41,17 +42,14 @@
#define MAX_TRIES 100
struct omap_sr {
- int srid;
- int is_sr_reset;
- int is_autocomp_active;
- struct clk *clk;
- struct clk *vdd_opp_clk;
- u32 clk_length;
- u32 req_opp_no;
- u32 opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue;
- u32 opp5_nvalue;
- u32 senp_mod, senn_mod;
- void __iomem *srbase_addr;
+ int srid;
+ int is_sr_reset;
+ int is_autocomp_active;
+ struct clk *vdd_opp_clk;
+ u32 clk_length;
+ void __iomem *srbase_addr;
+ unsigned int irq;
+ struct platform_device *pdev;
struct list_head node;
};
@@ -98,71 +96,22 @@ static struct omap_sr *_sr_lookup(int srid)
static int sr_clk_enable(struct omap_sr *sr)
{
- if (clk_enable(sr->clk) != 0) {
- pr_err("Could not enable %s\n", sr->clk->name);
- return -1;
- }
+ struct omap_smartreflex_data *pdata = sr->pdev->dev.platform_data;
- /* set fclk- active , iclk- idle */
- sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
- SR_CLKACTIVITY_IOFF_FON);
+ if (pdata->device_enable)
+ pdata->device_enable(sr->pdev);
return 0;
}
static void sr_clk_disable(struct omap_sr *sr)
{
- /* set fclk, iclk- idle */
- sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
- SR_CLKACTIVITY_IOFF_FOFF);
-
- clk_disable(sr->clk);
- sr->is_sr_reset = 1;
-}
+ struct omap_smartreflex_data *pdata = sr->pdev->dev.platform_data;
-static struct omap_sr sr1 = {
- .srid = SR1,
- .is_sr_reset = 1,
- .is_autocomp_active = 0,
- .clk_length = 0,
- .srbase_addr = OMAP2_L4_IO_ADDRESS(OMAP34XX_SR1_BASE),
-};
-
-static struct omap_sr sr2 = {
- .srid = SR2,
- .is_sr_reset = 1,
- .is_autocomp_active = 0,
- .clk_length = 0,
- .srbase_addr = OMAP2_L4_IO_ADDRESS(OMAP34XX_SR2_BASE),
-};
+ if (pdata->device_idle)
+ pdata->device_idle(sr->pdev);
-static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen)
-{
- u32 gn, rn, mul;
-
- for (gn = 0; gn < GAIN_MAXLIMIT; gn++) {
- mul = 1 << (gn + 8);
- rn = mul / sensor;
- if (rn < R_MAXLIMIT) {
- *sengain = gn;
- *rnsen = rn;
- }
- }
-}
-
-static u32 cal_test_nvalue(u32 sennval, u32 senpval)
-{
- u32 senpgain, senngain;
- u32 rnsenp, rnsenn;
-
- /* Calculating the gain and reciprocal of the SenN and SenP values */
- cal_reciprocal(senpval, &senpgain, &rnsenp);
- cal_reciprocal(sennval, &senngain, &rnsenn);
-
- return (senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
- (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
- (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
- (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT);
+ sr->is_sr_reset = 1;
}
static u8 get_vdd1_opp(void)
@@ -255,76 +204,6 @@ static void sr_set_clk_length(struct omap_sr *sr)
}
}
-static void sr_set_efuse_nvalues(struct omap_sr *sr)
-{
- if (sr->srid == SR1) {
- sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
- OMAP343X_SR1_SENNENABLE_MASK) >>
- OMAP343X_SR1_SENNENABLE_SHIFT;
- sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
- OMAP343X_SR1_SENPENABLE_MASK) >>
- OMAP343X_SR1_SENPENABLE_SHIFT;
-
- sr->opp5_nvalue = omap_ctrl_readl(
- OMAP343X_CONTROL_FUSE_OPP5_VDD1);
- sr->opp4_nvalue = omap_ctrl_readl(
- OMAP343X_CONTROL_FUSE_OPP4_VDD1);
- sr->opp3_nvalue = omap_ctrl_readl(
- OMAP343X_CONTROL_FUSE_OPP3_VDD1);
- sr->opp2_nvalue = omap_ctrl_readl(
- OMAP343X_CONTROL_FUSE_OPP2_VDD1);
- sr->opp1_nvalue = omap_ctrl_readl(
- OMAP343X_CONTROL_FUSE_OPP1_VDD1);
- } else if (sr->srid == SR2) {
- sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
- OMAP343X_SR2_SENNENABLE_MASK) >>
- OMAP343X_SR2_SENNENABLE_SHIFT;
-
- sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
- OMAP343X_SR2_SENPENABLE_MASK) >>
- OMAP343X_SR2_SENPENABLE_SHIFT;
-
- sr->opp3_nvalue = omap_ctrl_readl(
- OMAP343X_CONTROL_FUSE_OPP3_VDD2);
- sr->opp2_nvalue = omap_ctrl_readl(
- OMAP343X_CONTROL_FUSE_OPP2_VDD2);
- sr->opp1_nvalue = omap_ctrl_readl(
- OMAP343X_CONTROL_FUSE_OPP1_VDD2);
- }
-}
-
-/* Hard coded nvalues for testing purposes, may cause device to hang! */
-static void sr_set_testing_nvalues(struct omap_sr *sr)
-{
- if (sr->srid == SR1) {
- sr->senp_mod = 0x03; /* SenN-M5 enabled */
- sr->senn_mod = 0x03;
-
- /* calculate nvalues for each opp */
- sr->opp5_nvalue = cal_test_nvalue(0xacd + 0x330, 0x848 + 0x330);
- sr->opp4_nvalue = cal_test_nvalue(0x964 + 0x2a0, 0x727 + 0x2a0);
- sr->opp3_nvalue = cal_test_nvalue(0x85b + 0x200, 0x655 + 0x200);
- sr->opp2_nvalue = cal_test_nvalue(0x506 + 0x1a0, 0x3be + 0x1a0);
- sr->opp1_nvalue = cal_test_nvalue(0x373 + 0x100, 0x28c + 0x100);
- } else if (sr->srid == SR2) {
- sr->senp_mod = 0x03;
- sr->senn_mod = 0x03;
-
- sr->opp3_nvalue = cal_test_nvalue(0x76f + 0x200, 0x579 + 0x200);
- sr->opp2_nvalue = cal_test_nvalue(0x4f5 + 0x1c0, 0x390 + 0x1c0);
- sr->opp1_nvalue = cal_test_nvalue(0x359, 0x25d);
- }
-
-}
-
-static void sr_set_nvalues(struct omap_sr *sr)
-{
- if (SR_TESTING_NVALUES)
- sr_set_testing_nvalues(sr);
- else
- sr_set_efuse_nvalues(sr);
-}
-
static void sr_configure_vp(int srid)
{
u32 vpconfig;
@@ -438,12 +317,13 @@ static void sr_configure(struct omap_sr *sr)
{
u32 sr_config;
u32 senp_en , senn_en;
+ struct omap_smartreflex_data *pdata = sr->pdev->dev.platform_data;
if (sr->clk_length == 0)
sr_set_clk_length(sr);
- senp_en = sr->senp_mod;
- senn_en = sr->senn_mod;
+ senp_en = pdata->senp_mod;
+ senn_en = pdata->senn_mod;
if (sr->srid == SR1) {
sr_config = SR1_SRCONFIG_ACCUMDATA |
(sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
@@ -571,57 +451,33 @@ static int sr_enable(struct omap_sr *sr, u32 target_opp_no)
{
u32 nvalue_reciprocal, v;
struct omap_opp *opp;
+ struct omap_smartreflex_data *pdata = sr->pdev->dev.platform_data;
int uvdc;
char vsel;
- sr->req_opp_no = target_opp_no;
-
if (sr->srid == SR1) {
- switch (target_opp_no) {
- case 5:
- nvalue_reciprocal = sr->opp5_nvalue;
- break;
- case 4:
- nvalue_reciprocal = sr->opp4_nvalue;
- break;
- case 3:
- nvalue_reciprocal = sr->opp3_nvalue;
- break;
- case 2:
- nvalue_reciprocal = sr->opp2_nvalue;
- break;
- case 1:
- nvalue_reciprocal = sr->opp1_nvalue;
- break;
- default:
- nvalue_reciprocal = sr->opp3_nvalue;
- break;
- }
-
opp = opp_find_by_opp_id(OPP_MPU, target_opp_no);
if (!opp)
return false;
} else {
- switch (target_opp_no) {
- case 3:
- nvalue_reciprocal = sr->opp3_nvalue;
- break;
- case 2:
- nvalue_reciprocal = sr->opp2_nvalue;
- break;
- case 1:
- nvalue_reciprocal = sr->opp1_nvalue;
- break;
- default:
- nvalue_reciprocal = sr->opp3_nvalue;
- break;
- }
-
opp = opp_find_by_opp_id(OPP_L3, target_opp_no);
if (!opp)
return false;
}
+ if (target_opp_no > pdata->no_opp) {
+ pr_notice("Wrong target opp\n");
+ return false;
+ }
+
+ if (!pdata->sr_nvalue) {
+ pr_notice("N target values does not exist for SR%d\n",
+ sr->srid);
+ return false;
+ }
+
+ nvalue_reciprocal = pdata->sr_nvalue[target_opp_no - 1];
+
if (nvalue_reciprocal == 0) {
pr_notice("OPP%d doesn't support SmartReflex\n",
target_opp_no);
@@ -1033,49 +889,255 @@ static struct kobj_attribute sr_vdd2_autocomp = {
.store = omap_sr_vdd2_autocomp_store,
};
+static int __devinit omap_smartreflex_probe(struct platform_device *pdev)
+{
+ struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL);
+ struct omap_device *odev = to_omap_device(pdev);
+ int ret = 0;
+
+ if (WARN_ON(!sr_info))
+ return -ENOMEM;
+ sr_info->pdev = pdev;
+ sr_info->srid = pdev->id + 1;
+ sr_info->is_sr_reset = 1,
+ sr_info->is_autocomp_active = 0;
+ sr_info->clk_length = 0;
+ sr_info->srbase_addr = odev->hwmods[0]->_rt_va;
+ if (odev->hwmods[0]->mpu_irqs)
+ sr_info->irq = odev->hwmods[0]->mpu_irqs[0].irq;
+ sr_set_clk_length(sr_info);
+
+ if (sr_info->srid == SR1) {
+ sr_info->vdd_opp_clk = clk_get(NULL, "dpll1_ck");
+ ret = sysfs_create_file(power_kobj, &sr_vdd1_autocomp.attr);
+ if (ret)
+ pr_err("sysfs_create_file failed: %d\n", ret);
+ } else {
+ sr_info->vdd_opp_clk = clk_get(NULL, "l3_ick");
+ ret = sysfs_create_file(power_kobj, &sr_vdd2_autocomp.attr);
+ if (ret)
+ pr_err("sysfs_create_file failed: %d\n", ret);
+ }
+
+ /* Call the VPConfig */
+ sr_configure_vp(sr_info->srid);
+ odev->hwmods[0]->dev_attr = sr_info;
+ list_add(&sr_info->node, &sr_list);
+ pr_info("SmartReflex driver initialized\n");
+
+ return ret;
+}
+
+static int __devexit omap_smartreflex_remove(struct platform_device *pdev)
+{
+ struct omap_device *odev = to_omap_device(pdev);
+ struct omap_sr *sr_info = odev->hwmods[0]->dev_attr;
+
+ /* Disable Autocompensation if enabled before removing the module */
+ if (sr_info->is_autocomp_active == 1)
+ sr_stop_vddautocomap(sr_info->srid);
+ list_del(&sr_info->node);
+ return 0;
+}
+static struct platform_driver smartreflex_driver = {
+ .probe = omap_smartreflex_probe,
+ .remove = omap_smartreflex_remove,
+ .driver = {
+ .name = "smartreflex",
+ },
+};
-static int __init omap3_sr_init(void)
+static int __init sr_init(void)
{
int ret = 0;
u8 RdReg;
+ /* TODO: Find an appropriate place for this */
/* Enable SR on T2 */
ret = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &RdReg,
R_DCDC_GLOBAL_CFG);
-
RdReg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX;
ret |= twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, RdReg,
R_DCDC_GLOBAL_CFG);
- if (cpu_is_omap34xx()) {
- sr1.clk = clk_get(NULL, "sr1_fck");
- sr2.clk = clk_get(NULL, "sr2_fck");
- }
- sr1.vdd_opp_clk = clk_get(NULL, "dpll1_ck");
- sr2.vdd_opp_clk = clk_get(NULL, "l3_ick");
- sr_set_clk_length(&sr1);
- sr_set_clk_length(&sr2);
- /* Call the VPConfig, VCConfig, set N Values. */
- sr_set_nvalues(&sr1);
- sr_configure_vp(SR1);
+ ret = platform_driver_probe(&smartreflex_driver,
+ omap_smartreflex_probe);
- sr_set_nvalues(&sr2);
- sr_configure_vp(SR2);
+ if (ret)
+ pr_err("platform driver register failed for smartreflex");
+ return 0;
+}
- pr_info("SmartReflex driver initialized\n");
+void __exit sr_exit(void)
+{
+ platform_driver_unregister(&smartreflex_driver);
+}
+late_initcall(sr_init);
+module_exit(sr_exit);
- ret = sysfs_create_file(power_kobj, &sr_vdd1_autocomp.attr);
- if (ret)
- pr_err("sysfs_create_file failed: %d\n", ret);
+MODULE_DESCRIPTION("OMAP SMARTREFLEX DRIVER");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Texas Instruments Inc");
- ret = sysfs_create_file(power_kobj, &sr_vdd2_autocomp.attr);
- if (ret)
- pr_err("sysfs_create_file failed: %d\n", ret);
- list_add(&sr1.node, &sr_list);
- list_add(&sr2.node, &sr_list);
+/* Device registrations for smartreflex instances */
- return 0;
+#define MAX_HWMOD_NAME_LEN 16
+
+struct omap_device_pm_latency omap_sr_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST
+ },
+};
+
+/* Read EFUSE values from control registers */
+static void __init omap3_sr_read_efuse(struct omap_smartreflex_data *sr_data,
+ int sr_id)
+{
+ if (sr_id == SR1) {
+ /*
+ * TODO: When opp framework come into picture use appropriate
+ * API's to find out number of opp's.
+ */
+ sr_data->no_opp = 5;
+ sr_data->sr_nvalue = kzalloc(sizeof(sr_data->sr_nvalue) *
+ sr_data->no_opp , GFP_KERNEL);
+ if (WARN_ON(!sr_data->sr_nvalue))
+ return;
+
+ sr_data->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+ OMAP343X_SR1_SENNENABLE_MASK) >>
+ OMAP343X_SR1_SENNENABLE_SHIFT;
+ sr_data->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+ OMAP343X_SR1_SENPENABLE_MASK) >>
+ OMAP343X_SR1_SENPENABLE_SHIFT;
+ sr_data->sr_nvalue[4] = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP5_VDD1);
+ sr_data->sr_nvalue[3] = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP4_VDD1);
+ sr_data->sr_nvalue[2] = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP3_VDD1);
+ sr_data->sr_nvalue[1] = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP2_VDD1);
+ sr_data->sr_nvalue[0] = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP1_VDD1);
+ } else if (sr_id == SR2) {
+ /*
+ * TODO: When opp framework come into picture use appropriate
+ * API's to find out number of opp's.
+ */
+ sr_data->no_opp = 3;
+ sr_data->sr_nvalue = kzalloc(sizeof(sr_data->sr_nvalue) *
+ sr_data->no_opp , GFP_KERNEL);
+ if (WARN_ON(!sr_data->sr_nvalue))
+ return;
+
+ sr_data->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+ OMAP343X_SR2_SENNENABLE_MASK) >>
+ OMAP343X_SR2_SENNENABLE_SHIFT;
+ sr_data->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+ OMAP343X_SR2_SENPENABLE_MASK) >>
+ OMAP343X_SR2_SENPENABLE_SHIFT;
+ sr_data->sr_nvalue[2] = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP3_VDD2);
+ sr_data->sr_nvalue[1] = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP2_VDD2);
+ sr_data->sr_nvalue[0] = omap_ctrl_readl(
+ OMAP343X_CONTROL_FUSE_OPP1_VDD2);
+ }
}
-late_initcall(omap3_sr_init);
+/* Hard coded nvalues for testing purposes, may cause device to hang! */
+static void __init omap3_sr_set_testing_nvalues(
+ struct omap_smartreflex_data *sr_data, int srid)
+{
+ if (srid == SR1) {
+ /*
+ * TODO: When opp framework come into picture use appropriate
+ * API's to find out number of opp's.
+ */
+ sr_data->no_opp = 5;
+ sr_data->sr_nvalue = kzalloc(sizeof(sr_data->sr_nvalue) *
+ sr_data->no_opp , GFP_KERNEL);
+ if (WARN_ON(!sr_data->sr_nvalue))
+ return;
+
+ sr_data->senp_mod = 0x03; /* SenN-M5 enabled */
+ sr_data->senn_mod = 0x03;
+ /* calculate nvalues for each opp */
+ sr_data->sr_nvalue[4] = 0x0;
+ sr_data->sr_nvalue[3] = 0x0;
+ sr_data->sr_nvalue[2] = 0x0;
+ sr_data->sr_nvalue[1] = 0x0;
+ sr_data->sr_nvalue[0] = 0x0;
+ } else if (srid == SR2) {
+ /*
+ * TODO: When opp framework come into picture use appropriate
+ * API's to find out number of opp's.
+ */
+ sr_data->no_opp = 3;
+ sr_data->sr_nvalue = kzalloc(sizeof(sr_data->sr_nvalue) *
+ sr_data->no_opp , GFP_KERNEL);
+ if (WARN_ON(!sr_data->sr_nvalue))
+ return;
+
+ sr_data->senp_mod = 0x03; /* SenN-M5 enabled */
+ sr_data->senn_mod = 0x03;
+ sr_data->sr_nvalue[2] = 0x0;
+ sr_data->sr_nvalue[1] = 0x0;
+ sr_data->sr_nvalue[0] = 0x0;
+ }
+}
+
+static void __init sr_set_nvalues(struct omap_smartreflex_data *sr_data,
+ int srid)
+{
+ if (cpu_is_omap343x()) {
+ if (SR_TESTING_NVALUES)
+ omap3_sr_set_testing_nvalues(sr_data, srid);
+ else
+ omap3_sr_read_efuse(sr_data, srid);
+ }
+}
+
+static int __init omap_devinit_smartreflex(void)
+{
+ int i = 0;
+ char *name = "smartreflex";
+
+ do {
+ struct omap_smartreflex_data *sr_data;
+ struct omap_device *od;
+ struct omap_hwmod *oh;
+ char oh_name[MAX_HWMOD_NAME_LEN];
+
+ snprintf(oh_name, MAX_HWMOD_NAME_LEN, "sr%d_hwmod", i + 1);
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh)
+ break;
+
+ sr_data = kzalloc(sizeof(struct omap_smartreflex_data),
+ GFP_KERNEL);
+ if (WARN_ON(!sr_data))
+ return -ENOMEM;
+
+ sr_data->init_enable = false;
+ sr_data->device_enable = omap_device_enable;
+ sr_data->device_shutdown = omap_device_shutdown;
+ sr_data->device_idle = omap_device_idle;
+ sr_set_nvalues(sr_data, i + 1);
+
+ od = omap_device_build(name, i, oh, sr_data, sizeof(*sr_data),
+ omap_sr_latency,
+ ARRAY_SIZE(omap_sr_latency));
+ WARN(IS_ERR(od), "Could not build omap_device for %s: %s.\n",
+ name, oh->name);
+ i++;
+ } while (1);
+
+ return 0;
+}
+arch_initcall(omap_devinit_smartreflex);
@@ -14,6 +14,8 @@
* published by the Free Software Foundation.
*/
+#include <linux/platform_device.h>
+
#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36)
#define PHY_TO_OFF_PM_RECIEVER(p) (p - 0x5b)
#define PHY_TO_OFF_PM_INT(p) (p - 0x2e)
@@ -243,6 +245,31 @@ extern u32 current_vdd2_opp;
* do anything.
*/
#ifdef CONFIG_OMAP_SMARTREFLEX
+/*
+ * omap_smartreflex_data - Smartreflex platform data
+ *
+ * @senp_mod : SENPENABLE value for the sr
+ * @senn_mod : SENNENABLE value for sr
+ * @sr_nvalue : array of n target values for sr
+ * @no_opp : number of opp's for this SR
+ * @init_enable : whether this sr module needs to enabled at boot up or not
+ * @device_enable : fn pointer to be populated with omap_device
+ * enable API
+ * @device_shutdown : fn pointer to be populated with omap_device
+ * shutdown API
+ * @device_idle : fn pointer to be pouplated with omap_device idle API
+ */
+struct omap_smartreflex_data {
+ u32 senp_mod;
+ u32 senn_mod;
+ u32 *sr_nvalue;
+ int no_opp;
+ bool init_enable;
+ int (*device_enable)(struct platform_device *pdev);
+ int (*device_shutdown)(struct platform_device *pdev);
+ int (*device_idle)(struct platform_device *pdev);
+};
+
void enable_smartreflex(int srid);
void disable_smartreflex(int srid);
int sr_voltagescale_vcbypass(u32 t_opp, u32 c_opp, u8 t_vsel, u8 c_vsel);