1
0
mirror of https://git.yoctoproject.org/meta-ti synced 2026-05-30 23:40:29 +00:00

linux-omap-2.6.39: remove old beagleboard-specific and not supported kernel

Beagleboard is supported by newer 3.x kernel recipes.

Signed-off-by: Denys Dmytriyenko <denys@ti.com>
Acked-by: Franklin Cooper Jr. <fcooper@ti.com>
This commit is contained in:
Denys Dmytriyenko
2013-09-28 15:54:37 -04:00
parent 4b78ad59df
commit 8c96f41ba6
95 changed files with 0 additions and 29857 deletions
@@ -1,117 +0,0 @@
From 16c1bdb30f1bcd750b29dffd2ef3003be2d30610 Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Fri, 20 May 2011 12:48:37 +0200
Subject: [PATCH 1/7] OMAP3: beagle: add support for beagleboard xM revision C
The USB enable GPIO has been inverted and the USER button moved.
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/board-omap3beagle.c | 34 +++++++++++++++++++++++-------
1 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 2de4b02..77bafa8 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -62,7 +62,9 @@
* AXBX = GPIO173, GPIO172, GPIO171: 1 1 1
* C1_3 = GPIO173, GPIO172, GPIO171: 1 1 0
* C4 = GPIO173, GPIO172, GPIO171: 1 0 1
- * XM = GPIO173, GPIO172, GPIO171: 0 0 0
+ * XMA = GPIO173, GPIO172, GPIO171: 0 0 0
+ * XMB = GPIO173, GPIO172, GPIO171: 0 0 1
+ * XMC = GPIO173, GPIO172, GPIO171: 0 1 0
*/
enum {
OMAP3BEAGLE_BOARD_UNKN = 0,
@@ -70,6 +72,7 @@ enum {
OMAP3BEAGLE_BOARD_C1_3,
OMAP3BEAGLE_BOARD_C4,
OMAP3BEAGLE_BOARD_XM,
+ OMAP3BEAGLE_BOARD_XMC,
};
static u8 omap3_beagle_version;
@@ -124,9 +127,18 @@ static void __init omap3_beagle_init_rev(void)
printk(KERN_INFO "OMAP3 Beagle Rev: xM\n");
omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
break;
+ case 1:
+ printk(KERN_INFO "OMAP3 Beagle Rev: xM B\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
+ break;
+ case 2:
+ printk(KERN_INFO "OMAP3 Beagle Rev: xM C\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
+ break;
default:
- printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
- omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+ printk(KERN_INFO
+ "OMAP3 Beagle Rev: unknown %hd, assuming xM C or newer\n", beagle_rev);
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
}
return;
@@ -278,7 +290,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
{
int r;
- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+ if (cpu_is_omap3630()) {
mmc[0].gpio_wp = -EINVAL;
} else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
(omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) {
@@ -298,7 +310,8 @@ static int beagle_twl_gpio_setup(struct device *dev,
/* REVISIT: need ehci-omap hooks for external VBUS
* power switch and overcurrent detect
*/
- if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) {
+ if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM
+ && omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XMC) {
r = gpio_request(gpio + 1, "EHCI_nOC");
if (!r) {
r = gpio_direction_input(gpio + 1);
@@ -320,7 +333,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
/* DVI reset GPIO is different between beagle revisions */
- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
+ if (cpu_is_omap3630())
beagle_dvi_device.reset_gpio = 129;
else
beagle_dvi_device.reset_gpio = 170;
@@ -334,7 +347,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
* P7/P8 revisions(prototype): Camera EN
* A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
*/
- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+ if (cpu_is_omap3630()) {
r = gpio_request(gpio + 1, "nDVI_PWR_EN");
if (!r) {
r = gpio_direction_output(gpio + 1, 0);
@@ -625,7 +638,7 @@ static void __init beagle_opp_init(void)
}
/* Custom OPP enabled for XM */
- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+ if (cpu_is_omap3630()) {
struct omap_hwmod *mh = omap_hwmod_lookup("mpu");
struct omap_hwmod *dh = omap_hwmod_lookup("iva");
struct device *dev;
@@ -665,6 +678,11 @@ static void __init omap3_beagle_init(void)
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
omap3_beagle_init_rev();
omap3_beagle_i2c_init();
+
+ if (cpu_is_omap3630()) {
+ gpio_buttons[0].gpio = 4;
+ }
+
platform_add_devices(omap3_beagle_devices,
ARRAY_SIZE(omap3_beagle_devices));
omap_display_init(&beagle_dss_data);
--
1.6.6.1
@@ -1,359 +0,0 @@
From 27494059a5d005b8cad4e0e8640ff031b86220dc Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Fri, 20 May 2011 13:06:24 +0200
Subject: [PATCH 2/7] OMAP3: beagle: add support for expansionboards
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/board-omap3beagle.c | 272 ++++++++++++++++++++++++++++++-
1 files changed, 269 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 77bafa8..db285e1 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/leds.h>
#include <linux/gpio.h>
+#include <linux/irq.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/opp.h>
@@ -154,6 +155,167 @@ fail0:
return;
}
+char expansionboard_name[16];
+
+#if defined(CONFIG_WL12XX) || defined(CONFIG_WL12XX_MODULE)
+#include <linux/regulator/fixed.h>
+#include <linux/wl12xx.h>
+
+#define OMAP_BEAGLE_WLAN_EN_GPIO (139)
+#define OMAP_BEAGLE_BT_EN_GPIO (138)
+#define OMAP_BEAGLE_WLAN_IRQ_GPIO (137)
+#define OMAP_BEAGLE_FM_EN_BT_WU (136)
+
+struct wl12xx_platform_data omap_beagle_wlan_data __initdata = {
+ .irq = OMAP_GPIO_IRQ(OMAP_BEAGLE_WLAN_IRQ_GPIO),
+ .board_ref_clock = 2, /* 38.4 MHz */
+};
+
+static int gpios[] = {OMAP_BEAGLE_BT_EN_GPIO, OMAP_BEAGLE_FM_EN_BT_WU, -1};
+static struct platform_device wl12xx_device = {
+ .name = "kim",
+ .id = -1,
+ .dev.platform_data = &gpios,
+};
+
+static struct omap2_hsmmc_info mmcbbt[] = {
+ {
+ .mmc = 1,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .gpio_wp = 29,
+ },
+ {
+ .name = "wl1271",
+ .mmc = 2,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
+ .gpio_wp = -EINVAL,
+ .gpio_cd = -EINVAL,
+ .ocr_mask = MMC_VDD_165_195,
+ .nonremovable = true,
+ },
+ {} /* Terminator */
+ };
+
+static struct regulator_consumer_supply beagle_vmmc2_supply =
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
+
+static struct regulator_init_data beagle_vmmc2 = {
+ .constraints = {
+ .min_uV = 1850000,
+ .max_uV = 1850000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &beagle_vmmc2_supply,
+};
+
+static struct fixed_voltage_config beagle_vwlan = {
+ .supply_name = "vwl1271",
+ .microvolts = 1800000, /* 1.8V */
+ .gpio = OMAP_BEAGLE_WLAN_EN_GPIO,
+ .startup_delay = 70000, /* 70ms */
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &beagle_vmmc2,
+};
+
+static struct platform_device omap_vwlan_device = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &beagle_vwlan,
+ },
+};
+#endif
+
+#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
+
+#include <plat/mcspi.h>
+#include <linux/spi/spi.h>
+
+#define OMAP3BEAGLE_GPIO_ENC28J60_IRQ 157
+
+static struct omap2_mcspi_device_config enc28j60_spi_chip_info = {
+ .turbo_mode = 0,
+ .single_channel = 1, /* 0: slave, 1: master */
+};
+
+static struct spi_board_info omap3beagle_zippy_spi_board_info[] __initdata = {
+ {
+ .modalias = "enc28j60",
+ .bus_num = 4,
+ .chip_select = 0,
+ .max_speed_hz = 20000000,
+ .controller_data = &enc28j60_spi_chip_info,
+ },
+};
+
+static void __init omap3beagle_enc28j60_init(void)
+{
+ if ((gpio_request(OMAP3BEAGLE_GPIO_ENC28J60_IRQ, "ENC28J60_IRQ") == 0) &&
+ (gpio_direction_input(OMAP3BEAGLE_GPIO_ENC28J60_IRQ) == 0)) {
+ gpio_export(OMAP3BEAGLE_GPIO_ENC28J60_IRQ, 0);
+ omap3beagle_zippy_spi_board_info[0].irq = OMAP_GPIO_IRQ(OMAP3BEAGLE_GPIO_ENC28J60_IRQ);
+ irq_set_irq_type(omap3beagle_zippy_spi_board_info[0].irq, IRQ_TYPE_EDGE_FALLING);
+ } else {
+ printk(KERN_ERR "could not obtain gpio for ENC28J60_IRQ\n");
+ return;
+ }
+
+ spi_register_board_info(omap3beagle_zippy_spi_board_info,
+ ARRAY_SIZE(omap3beagle_zippy_spi_board_info));
+}
+
+#else
+static inline void __init omap3beagle_enc28j60_init(void) { return; }
+#endif
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+
+#include <plat/mcspi.h>
+#include <linux/spi/spi.h>
+
+#define OMAP3BEAGLE_GPIO_KS8851_IRQ 157
+
+static struct omap2_mcspi_device_config ks8851_spi_chip_info = {
+ .turbo_mode = 0,
+ .single_channel = 1, /* 0: slave, 1: master */
+};
+
+static struct spi_board_info omap3beagle_zippy2_spi_board_info[] __initdata = {
+ {
+ .modalias = "ks8851",
+ .bus_num = 4,
+ .chip_select = 0,
+ .max_speed_hz = 36000000,
+ .controller_data = &ks8851_spi_chip_info,
+ },
+};
+
+static void __init omap3beagle_ks8851_init(void)
+{
+ if ((gpio_request(OMAP3BEAGLE_GPIO_KS8851_IRQ, "KS8851_IRQ") == 0) &&
+ (gpio_direction_input(OMAP3BEAGLE_GPIO_KS8851_IRQ) == 0)) {
+ gpio_export(OMAP3BEAGLE_GPIO_KS8851_IRQ, 0);
+ omap3beagle_zippy2_spi_board_info[0].irq = OMAP_GPIO_IRQ(OMAP3BEAGLE_GPIO_KS8851_IRQ);
+ irq_set_irq_type(omap3beagle_zippy2_spi_board_info[0].irq, IRQ_TYPE_EDGE_FALLING);
+ } else {
+ printk(KERN_ERR "could not obtain gpio for KS8851_IRQ\n");
+ return;
+ }
+
+ spi_register_board_info(omap3beagle_zippy2_spi_board_info,
+ ARRAY_SIZE(omap3beagle_zippy2_spi_board_info));
+}
+
+#else
+static inline void __init omap3beagle_ks8851_init(void) { return; }
+#endif
+
static struct mtd_partition omap3beagle_nand_partitions[] = {
/* All the partition sizes are listed in terms of NAND block size */
{
@@ -272,6 +434,12 @@ static struct omap2_hsmmc_info mmc[] = {
.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_wp = 29,
},
+ {
+ .mmc = 2,
+ .caps = MMC_CAP_4_BIT_DATA,
+ .transceiver = true,
+ .ocr_mask = 0x00100000, /* 3.3V */
+ },
{} /* Terminator */
};
@@ -301,11 +469,25 @@ static int beagle_twl_gpio_setup(struct device *dev,
}
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
mmc[0].gpio_cd = gpio + 0;
+#if defined(CONFIG_WL12XX) || defined(CONFIG_WL12XX_MODULE)
+ if(!strcmp(expansionboard_name, "bbtoys-wifi")) {
+ omap2_hsmmc_init(mmcbbt);
+ /* link regulators to MMC adapters */
+ beagle_vmmc1_supply.dev = mmcbbt[0].dev;
+ beagle_vsim_supply.dev = mmcbbt[0].dev;
+ } else {
+ omap2_hsmmc_init(mmc);
+ /* link regulators to MMC adapters */
+ beagle_vmmc1_supply.dev = mmc[0].dev;
+ beagle_vsim_supply.dev = mmc[0].dev;
+ }
+#else
omap2_hsmmc_init(mmc);
/* link regulators to MMC adapters */
beagle_vmmc1_supply.dev = mmc[0].dev;
beagle_vsim_supply.dev = mmc[0].dev;
+#endif
/* REVISIT: need ehci-omap hooks for external VBUS
* power switch and overcurrent detect
@@ -466,7 +648,7 @@ static struct twl4030_platform_data beagle_twldata = {
.vpll2 = &beagle_vpll2,
};
-static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
+static struct i2c_board_info __initdata beagle_i2c1_boardinfo[] = {
{
I2C_BOARD_INFO("twl4030", 0x48),
.flags = I2C_CLIENT_WAKE,
@@ -481,10 +663,24 @@ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
},
};
+#if defined(CONFIG_RTC_DRV_DS1307) || \
+ defined(CONFIG_RTC_DRV_DS1307_MODULE)
+
+static struct i2c_board_info __initdata beagle_i2c2_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("ds1307", 0x68),
+ },
+};
+#else
+static struct i2c_board_info __initdata beagle_i2c2_boardinfo[] = {};
+#endif
+
static int __init omap3_beagle_i2c_init(void)
{
- omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
- ARRAY_SIZE(beagle_i2c_boardinfo));
+ omap_register_i2c_bus(1, 2600, beagle_i2c1_boardinfo,
+ ARRAY_SIZE(beagle_i2c1_boardinfo));
+ omap_register_i2c_bus(2, 400, beagle_i2c2_boardinfo,
+ ARRAY_SIZE(beagle_i2c2_boardinfo));
/* Bus 3 is attached to the DVI port where devices like the pico DLP
* projector don't work reliably with 400kHz */
omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
@@ -627,6 +823,15 @@ static struct omap_musb_board_data musb_board_data = {
.power = 100,
};
+static int __init expansionboard_setup(char *str)
+{
+ if (!str)
+ return -EINVAL;
+ strncpy(expansionboard_name, str, 16);
+ printk(KERN_INFO "Beagle expansionboard: %s\n", expansionboard_name);
+ return 0;
+}
+
static void __init beagle_opp_init(void)
{
int r = 0;
@@ -693,6 +898,65 @@ static void __init omap3_beagle_init(void)
/* REVISIT leave DVI powered down until it's needed ... */
gpio_direction_output(170, true);
+ if(!strcmp(expansionboard_name, "zippy"))
+ {
+ printk(KERN_INFO "Beagle expansionboard: initializing enc28j60\n");
+ omap3beagle_enc28j60_init();
+ printk(KERN_INFO "Beagle expansionboard: assigning GPIO 141 and 162 to MMC1\n");
+ mmc[1].gpio_wp = 141;
+ mmc[1].gpio_cd = 162;
+ }
+
+ if(!strcmp(expansionboard_name, "zippy2"))
+ {
+ printk(KERN_INFO "Beagle expansionboard: initializing ks_8851\n");
+ omap3beagle_ks8851_init();
+ printk(KERN_INFO "Beagle expansionboard: assigning GPIO 141 and 162 to MMC1\n");
+ mmc[1].gpio_wp = 141;
+ mmc[1].gpio_cd = 162;
+ }
+
+ if(!strcmp(expansionboard_name, "trainer"))
+ {
+ printk(KERN_INFO "Beagle expansionboard: exporting GPIOs 130-141,162 to userspace\n");
+ gpio_request(130, "sysfs");
+ gpio_export(130, 1);
+ gpio_request(131, "sysfs");
+ gpio_export(131, 1);
+ gpio_request(132, "sysfs");
+ gpio_export(132, 1);
+ gpio_request(133, "sysfs");
+ gpio_export(133, 1);
+ gpio_request(134, "sysfs");
+ gpio_export(134, 1);
+ gpio_request(135, "sysfs");
+ gpio_export(135, 1);
+ gpio_request(136, "sysfs");
+ gpio_export(136, 1);
+ gpio_request(137, "sysfs");
+ gpio_export(137, 1);
+ gpio_request(138, "sysfs");
+ gpio_export(138, 1);
+ gpio_request(139, "sysfs");
+ gpio_export(139, 1);
+ gpio_request(140, "sysfs");
+ gpio_export(140, 1);
+ gpio_request(141, "sysfs");
+ gpio_export(141, 1);
+ gpio_request(162, "sysfs");
+ gpio_export(162, 1);
+ }
+
+ if(!strcmp(expansionboard_name, "bbtoys-wifi"))
+ {
+ if (wl12xx_set_platform_data(&omap_beagle_wlan_data))
+ pr_err("error setting wl12xx data\n");
+ printk(KERN_INFO "Beagle expansionboard: registering wl12xx bt platform device\n");
+ platform_device_register(&wl12xx_device);
+ printk(KERN_INFO "Beagle expansionboard: registering wl12xx wifi platform device\n");
+ platform_device_register(&omap_vwlan_device);
+ }
+
usb_musb_init(&musb_board_data);
usbhs_init(&usbhs_bdata);
omap3beagle_flash_init();
@@ -705,6 +969,8 @@ static void __init omap3_beagle_init(void)
beagle_opp_init();
}
+early_param("buddy", expansionboard_setup);
+
MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
/* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
.boot_params = 0x80000100,
--
1.6.6.1
@@ -1,36 +0,0 @@
From 91e701f3287923d11dd295b6a62186909e362503 Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Sat, 21 May 2011 16:18:30 +0200
Subject: [PATCH 3/7] OMAP3: beagle: add MADC support
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/board-omap3beagle.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index db285e1..da4ba50 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -634,6 +634,10 @@ static struct twl4030_codec_data beagle_codec_data = {
.audio = &beagle_audio_data,
};
+static struct twl4030_madc_platform_data beagle_madc_data = {
+ .irq_line = 1,
+};
+
static struct twl4030_platform_data beagle_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
@@ -642,6 +646,7 @@ static struct twl4030_platform_data beagle_twldata = {
.usb = &beagle_usb_data,
.gpio = &beagle_gpio_data,
.codec = &beagle_codec_data,
+ .madc = &beagle_madc_data,
.vmmc1 = &beagle_vmmc1,
.vsim = &beagle_vsim,
.vdac = &beagle_vdac,
--
1.6.6.1
@@ -1,88 +0,0 @@
From 9d7f46abab88c74e674461a2f4e9ab35b524a6ef Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Wed, 25 May 2011 08:56:06 +0200
Subject: [PATCH 4/7] OMAP3: beagle: add regulators for camera interface
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/board-omap3beagle.c | 50 +++++++++++++++++++++++++++++++
1 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index da4ba50..211cbdf 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -453,6 +453,44 @@ static struct regulator_consumer_supply beagle_vsim_supply = {
static struct gpio_led gpio_leds[];
+static struct regulator_consumer_supply beagle_vaux3_supply = {
+ .supply = "cam_1v8",
+};
+
+static struct regulator_consumer_supply beagle_vaux4_supply = {
+ .supply = "cam_2v8",
+};
+
+/* VAUX3 for CAM_1V8 */
+static struct regulator_init_data beagle_vaux3 = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &beagle_vaux3_supply,
+};
+
+/* VAUX4 for CAM_2V8 */
+static struct regulator_init_data beagle_vaux4 = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &beagle_vaux4_supply,
+};
+
static int beagle_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
@@ -504,6 +542,16 @@ static int beagle_twl_gpio_setup(struct device *dev,
pr_err("%s: unable to configure EHCI_nOC\n", __func__);
}
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+ /*
+ * Power on camera interface - only on pre-production, not
+ * needed on production boards
+ */
+ gpio_request(gpio + 2, "CAM_EN");
+ gpio_direction_output(gpio + 2, 1);
+ }
+
+
/*
* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
* high / others active low)
@@ -651,6 +699,8 @@ static struct twl4030_platform_data beagle_twldata = {
.vsim = &beagle_vsim,
.vdac = &beagle_vdac,
.vpll2 = &beagle_vpll2,
+ .vaux3 = &beagle_vaux3,
+ .vaux4 = &beagle_vaux4,
};
static struct i2c_board_info __initdata beagle_i2c1_boardinfo[] = {
--
1.6.6.1
@@ -1,31 +0,0 @@
From aa93263ed7827e33148396656b7e7ab4579509a5 Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Wed, 25 May 2011 08:57:40 +0200
Subject: [PATCH 5/7] OMAP3: beagle: HACK! add in 1GHz OPP
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/board-omap3beagle.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 211cbdf..221bfda 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -911,11 +911,13 @@ static void __init beagle_opp_init(void)
/* Enable MPU 1GHz and lower opps */
dev = &mh->od->pdev.dev;
r = opp_enable(dev, 800000000);
+ r |= opp_enable(dev, 1000000000);
/* TODO: MPU 1GHz needs SR and ABB */
/* Enable IVA 800MHz and lower opps */
dev = &dh->od->pdev.dev;
r |= opp_enable(dev, 660000000);
+ r |= opp_enable(dev, 800000000);
/* TODO: DSP 800MHz needs SR and ABB */
if (r) {
pr_err("%s: failed to enable higher opp %d\n",
--
1.6.6.1
@@ -1,27 +0,0 @@
From dd2c7ba245ec1b17e3d323a6c4a1cad9697dbbbe Mon Sep 17 00:00:00 2001
From: Koen Kooi <koen@dominion.thruhere.net>
Date: Wed, 15 Jun 2011 16:25:50 +0200
Subject: [PATCH 6/7] OMAP3: BEAGLE: fix RTC
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/board-omap3beagle.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 221bfda..61564a4 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -941,6 +941,9 @@ static void __init omap3_beagle_init(void)
omap3_beagle_init_rev();
omap3_beagle_i2c_init();
+ /* Ensure msecure is mux'd to be able to set the RTC. */
+ omap_mux_init_signal("sys_drm_msecure", OMAP_PIN_OFF_OUTPUT_HIGH);
+
if (cpu_is_omap3630()) {
gpio_buttons[0].gpio = 4;
}
--
1.6.6.1
@@ -1,33 +0,0 @@
From bd0b2f97c48aa6aac0c6a494f1c6ba5af5de486b Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Mon, 18 Jul 2011 23:13:41 -0500
Subject: [PATCH] omap_hsmmc: Set dto to max value of 14 to avoid SD Card timeouts
This fixes MMC errors due to timeouts on certain SD Cards following suggestions
to set dto to 14 by Jason Kridner and Steven Kipisz
Details of the issue:
http://talk.maemo.org/showthread.php?p=1000707#post1000707
This fix was originally proposed by Sukumar Ghoral of TI.
---
drivers/mmc/host/omap_hsmmc.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 9646a75..7443647 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1049,6 +1049,9 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
dto = 14;
}
+ /* Set dto to max value of 14 to avoid SD Card timeouts */
+ dto = 14;
+
reg &= ~DTO_MASK;
reg |= dto << DTO_SHIFT;
OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
--
1.7.0.4
@@ -1,42 +0,0 @@
From 101b0aedf8152711847e2f9f347d267a3ac7f287 Mon Sep 17 00:00:00 2001
From: Sanjeev Premi <premi@ti.com>
Date: Fri, 24 Jun 2011 16:23:45 +0000
Subject: [PATCH 7/7] omap3: beagle: Use GPTIMERi 1 for clockevents
The current selection of the GPTIMER on was result of
a hardware issue in early versions of the Beagleboards
(Ax and B1 thru B4). [1] [2]
Its been long since the hardware issue has been fixed.
This patch uses GPTIMER 1 for all newer board revisions
incl. Beagleboard XM.
[1] http://thread.gmane.org/gmane.comp.hardware.beagleboard.general/91
[2] Errata #7 at http://elinux.org/BeagleBoard#Errata
Signed-off-by: Sanjeev Premi <premi@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Reviewed-by: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/board-omap3beagle.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 61564a4..20d5912 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -806,7 +806,10 @@ static void __init omap3_beagle_init_irq(void)
{
omap_init_irq();
#ifdef CONFIG_OMAP_32K_TIMER
- omap2_gp_clockevent_set_gptimer(12);
+ if (omap3_beagle_version == OMAP3BEAGLE_BOARD_AXBX)
+ omap2_gp_clockevent_set_gptimer(12);
+ else
+ omap2_gp_clockevent_set_gptimer(1);
#endif
}
--
1.6.6.1
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,859 +0,0 @@
From e630a914bf14bf190feaf4a2cc57f6b27c4024e1 Mon Sep 17 00:00:00 2001
From: Javier Martin <javier.martin@vista-silicon.com>
Date: Wed, 1 Jun 2011 17:36:48 +0200
Subject: [PATCH 1/3] Add driver for Aptina (Micron) mt9p031 sensor.
Clock frequency of 57MHz used in previous version was wrong since
when VDD_IO is 1.8V it can only support 48MHz.
Two new platform flags have been added:
- vdd_io: indicates whether the chip is powered with 1.8 or 2.8 VDD_IO.
So that it can use the maximum allowed frequency.
- version: monochrome and color versions of the chip have exactly
the same ID, so the only way to select one of them is through
platform data.
Internal PLL is now used to generate PIXCLK depending on VDD_IO.
Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
drivers/media/video/Kconfig | 7 +
drivers/media/video/Makefile | 1 +
drivers/media/video/mt9p031.c | 763 +++++++++++++++++++++++++++++++++++++++++
include/media/mt9p031.h | 23 ++
4 files changed, 794 insertions(+), 0 deletions(-)
create mode 100644 drivers/media/video/mt9p031.c
create mode 100644 include/media/mt9p031.h
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 00f51dd..cb87e35 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -329,6 +329,13 @@ config VIDEO_OV7670
OV7670 VGA camera. It currently only works with the M88ALP01
controller.
+config VIDEO_MT9P031
+ tristate "Aptina MT9P031 support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Aptina
+ (Micron) mt9p031 5 Mpixel camera.
+
config VIDEO_MT9V011
tristate "Micron mt9v011 sensor support"
depends on I2C && VIDEO_V4L2
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ace5d8b..912b29b 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
+obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
new file mode 100644
index 0000000..cd830b1
--- /dev/null
+++ b/drivers/media/video/mt9p031.c
@@ -0,0 +1,763 @@
+/*
+ * Driver for MT9P031 CMOS Image Sensor from Aptina
+ *
+ * Copyright (C) 2011, Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Based on the MT9V032 driver and Bastian Hecht's code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <media/v4l2-subdev.h>
+#include <linux/videodev2.h>
+
+#include <media/mt9p031.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+
+#define MT9P031_EXTCLK_FREQ 20000000
+
+#define MT9P031_CHIP_VERSION 0x00
+#define MT9P031_CHIP_VERSION_VALUE 0x1801
+#define MT9P031_ROW_START 0x01
+#define MT9P031_ROW_START_MIN 1
+#define MT9P031_ROW_START_MAX 2004
+#define MT9P031_ROW_START_DEF 54
+#define MT9P031_COLUMN_START 0x02
+#define MT9P031_COLUMN_START_MIN 1
+#define MT9P031_COLUMN_START_MAX 2750
+#define MT9P031_COLUMN_START_DEF 16
+#define MT9P031_WINDOW_HEIGHT 0x03
+#define MT9P031_WINDOW_HEIGHT_MIN 2
+#define MT9P031_WINDOW_HEIGHT_MAX 2003
+#define MT9P031_WINDOW_HEIGHT_DEF 2003
+#define MT9P031_WINDOW_WIDTH 0x04
+#define MT9P031_WINDOW_WIDTH_MIN 18
+#define MT9P031_WINDOW_WIDTH_MAX 2751
+#define MT9P031_WINDOW_WIDTH_DEF 2751
+#define MT9P031_H_BLANKING 0x05
+#define MT9P031_H_BLANKING_VALUE 0
+#define MT9P031_V_BLANKING 0x06
+#define MT9P031_V_BLANKING_VALUE 25
+#define MT9P031_OUTPUT_CONTROL 0x07
+#define MT9P031_OUTPUT_CONTROL_CEN 2
+#define MT9P031_OUTPUT_CONTROL_SYN 1
+#define MT9P031_SHUTTER_WIDTH_UPPER 0x08
+#define MT9P031_SHUTTER_WIDTH 0x09
+#define MT9P031_PLL_CONTROL 0x10
+#define MT9P031_PLL_CONTROL_PWROFF 0x0050
+#define MT9P031_PLL_CONTROL_PWRON 0x0051
+#define MT9P031_PLL_CONTROL_USEPLL 0x0052
+#define MT9P031_PLL_CONFIG_1 0x11
+#define MT9P031_PLL_CONFIG_1_M_48MHZ 0x5000
+#define MT9P031_PLL_CONFIG_1_N_48MHZ 0x05
+#define MT9P031_PLL_CONFIG_1_M_96MHZ 0x3600
+#define MT9P031_PLL_CONFIG_1_N_96MHZ 0x05
+#define MT9P031_PLL_CONFIG_2 0x12
+#define MT9P031_PLL_CONFIG_2_P1_48MHZ 5
+#define MT9P031_PLL_CONFIG_2_P1_96MHZ 2
+#define MT9P031_PIXEL_CLOCK_CONTROL 0x0a
+#define MT9P031_FRAME_RESTART 0x0b
+#define MT9P031_SHUTTER_DELAY 0x0c
+#define MT9P031_RST 0x0d
+#define MT9P031_RST_ENABLE 1
+#define MT9P031_RST_DISABLE 0
+#define MT9P031_READ_MODE_1 0x1e
+#define MT9P031_READ_MODE_2 0x20
+#define MT9P031_READ_MODE_2_ROW_MIR 0x8000
+#define MT9P031_READ_MODE_2_COL_MIR 0x4000
+#define MT9P031_ROW_ADDRESS_MODE 0x22
+#define MT9P031_COLUMN_ADDRESS_MODE 0x23
+#define MT9P031_GLOBAL_GAIN 0x35
+
+struct mt9p031 {
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+ struct v4l2_rect rect; /* Sensor window */
+ struct v4l2_mbus_framefmt format;
+ struct mt9p031_platform_data *pdata;
+ struct mutex power_lock; /* lock to protect power_count */
+ int power_count;
+ u16 xskip;
+ u16 yskip;
+ /* cache register values */
+ u16 output_control;
+};
+
+static struct mt9p031 *to_mt9p031(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct mt9p031, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+ s32 data = i2c_smbus_read_word_data(client, reg);
+ return data < 0 ? data : swab16(data);
+}
+
+static int reg_write(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ return i2c_smbus_write_word_data(client, reg, swab16(data));
+}
+
+static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear,
+ u16 set)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+ u16 value = (mt9p031->output_control & ~clear) | set;
+ int ret;
+
+ ret = reg_write(client, MT9P031_OUTPUT_CONTROL, value);
+ if (ret < 0)
+ return ret;
+ mt9p031->output_control = value;
+ return 0;
+}
+
+static int mt9p031_reset(struct i2c_client *client)
+{
+ struct mt9p031 *mt9p031 = to_mt9p031(client);
+ int ret;
+
+ /* Disable chip output, synchronous option update */
+ ret = reg_write(client, MT9P031_RST, MT9P031_RST_ENABLE);
+ if (ret < 0)
+ return ret;
+ ret = reg_write(client, MT9P031_RST, MT9P031_RST_DISABLE);
+ if (ret < 0)
+ return ret;
+ return mt9p031_set_output_control(mt9p031,
+ MT9P031_OUTPUT_CONTROL_CEN, 0);
+}
+
+static int mt9p031_power_on(struct mt9p031 *mt9p031)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+ int ret;
+
+ /* Ensure RESET_BAR is low */
+ if (mt9p031->pdata->reset) {
+ mt9p031->pdata->reset(&mt9p031->subdev, 1);
+ msleep(1);
+ }
+ /* Emable clock */
+ if (mt9p031->pdata->set_xclk)
+ mt9p031->pdata->set_xclk(&mt9p031->subdev, MT9P031_EXTCLK_FREQ);
+ /* Now RESET_BAR must be high */
+ if (mt9p031->pdata->reset) {
+ mt9p031->pdata->reset(&mt9p031->subdev, 0);
+ msleep(1);
+ }
+ /* soft reset */
+ ret = mt9p031_reset(client);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to reset the camera\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void mt9p031_power_off(struct mt9p031 *mt9p031)
+{
+ if (mt9p031->pdata->reset) {
+ mt9p031->pdata->reset(&mt9p031->subdev, 1);
+ msleep(1);
+ }
+ if (mt9p031->pdata->set_xclk)
+ mt9p031->pdata->set_xclk(&mt9p031->subdev, 0);
+}
+
+static int mt9p031_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev);
+
+ if (code->pad || code->index)
+ return -EINVAL;
+
+ code->code = mt9p031->format.code;
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *mt9p031_get_pad_format(
+ struct mt9p031 *mt9p031,
+ struct v4l2_subdev_fh *fh,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(fh, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &mt9p031->format;
+ default:
+ return NULL;
+ }
+}
+
+static struct v4l2_rect *mt9p031_get_pad_crop(struct mt9p031 *mt9p031,
+ struct v4l2_subdev_fh *fh, unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(fh, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &mt9p031->rect;
+ default:
+ return NULL;
+ }
+}
+
+static int mt9p031_get_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev);
+ struct v4l2_rect *rect = mt9p031_get_pad_crop(mt9p031, fh, crop->pad,
+ crop->which);
+ if (!rect)
+ return -EINVAL;
+
+ crop->rect = *rect;
+
+ return 0;
+}
+
+static u16 mt9p031_skip_for_crop(s32 source, s32 *target, s32 max_skip)
+{
+ unsigned int skip;
+
+ if (source - source / 4 < *target) {
+ *target = source;
+ return 1;
+ }
+
+ skip = DIV_ROUND_CLOSEST(source, *target);
+ if (skip > max_skip)
+ skip = max_skip;
+ *target = 2 * DIV_ROUND_UP(source, 2 * skip);
+
+ return skip;
+}
+
+static int mt9p031_set_params(struct i2c_client *client,
+ struct v4l2_rect *rect, u16 xskip, u16 yskip)
+{
+ struct mt9p031 *mt9p031 = to_mt9p031(client);
+ int ret;
+ u16 xbin, ybin;
+ const u16 hblank = MT9P031_H_BLANKING_VALUE,
+ vblank = MT9P031_V_BLANKING_VALUE;
+ __s32 left;
+
+ /*
+ * TODO: Attention! When implementing horizontal flipping, adjust
+ * alignment according to R2 "Column Start" description in the datasheet
+ */
+ if (xskip & 1) {
+ xbin = 1;
+ left = rect->left & (~3);
+ } else if (xskip & 2) {
+ xbin = 2;
+ left = rect->left & (~7);
+ } else {
+ xbin = 4;
+ left = rect->left & (~15);
+ }
+ ybin = min(yskip, (u16)4);
+
+ /* Disable register update, reconfigure atomically */
+ ret = mt9p031_set_output_control(mt9p031, 0,
+ MT9P031_OUTPUT_CONTROL_SYN);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n",
+ xskip, yskip, rect->width, rect->height, rect->left, rect->top);
+
+ /* Blanking and start values - default... */
+ ret = reg_write(client, MT9P031_H_BLANKING, hblank);
+ if (ret < 0)
+ return ret;
+ ret = reg_write(client, MT9P031_V_BLANKING, vblank);
+ if (ret < 0)
+ return ret;
+
+ ret = reg_write(client, MT9P031_COLUMN_ADDRESS_MODE,
+ ((xbin - 1) << 4) | (xskip - 1));
+ if (ret < 0)
+ return ret;
+ ret = reg_write(client, MT9P031_ROW_ADDRESS_MODE,
+ ((ybin - 1) << 4) | (yskip - 1));
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&client->dev, "new physical left %u, top %u\n",
+ rect->left, rect->top);
+
+ ret = reg_write(client, MT9P031_COLUMN_START,
+ rect->left);
+ if (ret < 0)
+ return ret;
+ ret = reg_write(client, MT9P031_ROW_START,
+ rect->top);
+ if (ret < 0)
+ return ret;
+
+ ret = reg_write(client, MT9P031_WINDOW_WIDTH,
+ rect->width - 1);
+ if (ret < 0)
+ return ret;
+ ret = reg_write(client, MT9P031_WINDOW_HEIGHT,
+ rect->height - 1);
+ if (ret < 0)
+ return ret;
+
+ /* Re-enable register update, commit all changes */
+ ret = mt9p031_set_output_control(mt9p031,
+ MT9P031_OUTPUT_CONTROL_SYN, 0);
+ if (ret < 0)
+ return ret;
+
+ mt9p031->xskip = xskip;
+ mt9p031->yskip = yskip;
+ return ret;
+}
+
+static int mt9p031_set_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev);
+ struct v4l2_mbus_framefmt *f;
+ struct v4l2_rect *c;
+ struct v4l2_rect rect;
+ u16 xskip, yskip;
+ s32 width, height;
+
+ dev_dbg(mt9p031->subdev.v4l2_dev->dev, "%s(%ux%u@%u:%u : %u)\n",
+ __func__, crop->rect.width, crop->rect.height,
+ crop->rect.left, crop->rect.top, crop->which);
+
+ /*
+ * Clamp the crop rectangle boundaries and align them to a multiple of 2
+ * pixels.
+ */
+ rect.width = ALIGN(clamp(crop->rect.width,
+ MT9P031_WINDOW_WIDTH_MIN,
+ MT9P031_WINDOW_WIDTH_MAX), 2);
+ rect.height = ALIGN(clamp(crop->rect.height,
+ MT9P031_WINDOW_HEIGHT_MIN,
+ MT9P031_WINDOW_HEIGHT_MAX), 2);
+ rect.left = ALIGN(clamp(crop->rect.left,
+ MT9P031_COLUMN_START_MIN,
+ MT9P031_COLUMN_START_MAX), 2);
+ rect.top = ALIGN(clamp(crop->rect.top,
+ MT9P031_ROW_START_MIN,
+ MT9P031_ROW_START_MAX), 2);
+
+ c = mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which);
+
+ if (rect.width != c->width || rect.height != c->height) {
+ /*
+ * Reset the output image size if the crop rectangle size has
+ * been modified.
+ */
+ f = mt9p031_get_pad_format(mt9p031, fh, crop->pad,
+ crop->which);
+ width = f->width;
+ height = f->height;
+
+ xskip = mt9p031_skip_for_crop(rect.width, &width, 7);
+ yskip = mt9p031_skip_for_crop(rect.height, &height, 8);
+ } else {
+ xskip = mt9p031->xskip;
+ yskip = mt9p031->yskip;
+ f = NULL;
+ }
+ if (f) {
+ f->width = width;
+ f->height = height;
+ }
+
+ *c = rect;
+ crop->rect = rect;
+
+ mt9p031->xskip = xskip;
+ mt9p031->yskip = yskip;
+ mt9p031->rect = *c;
+ return 0;
+}
+
+static int mt9p031_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev);
+
+ fmt->format =
+ *mt9p031_get_pad_format(mt9p031, fh, fmt->pad, fmt->which);
+ return 0;
+}
+
+static u16 mt9p031_skip_for_scale(s32 *source, s32 target,
+ s32 max_skip, s32 max)
+{
+ unsigned int skip;
+
+ if (*source - *source / 4 < target) {
+ *source = target;
+ return 1;
+ }
+
+ skip = min(max, *source + target / 2) / target;
+ if (skip > max_skip)
+ skip = max_skip;
+ *source = target * skip;
+
+ return skip;
+}
+
+static int mt9p031_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *__format;
+ struct v4l2_rect *__crop, rect;
+ struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev);
+ unsigned int width;
+ unsigned int height;
+ u16 xskip, yskip;
+
+ __crop = mt9p031_get_pad_crop(mt9p031, fh, format->pad, format->which);
+
+ width = clamp_t(int, ALIGN(format->format.width, 2), 2,
+ MT9P031_WINDOW_WIDTH_MAX);
+ height = clamp_t(int, ALIGN(format->format.height, 2), 2,
+ MT9P031_WINDOW_HEIGHT_MAX);
+
+ rect.width = __crop->width;
+ rect.height = __crop->height;
+
+ xskip = mt9p031_skip_for_scale(&rect.width, width, 7,
+ MT9P031_WINDOW_WIDTH_MAX);
+ if (rect.width + __crop->left > MT9P031_WINDOW_WIDTH_MAX)
+ rect.left = (MT9P031_WINDOW_WIDTH_MAX - rect.width) / 2;
+ else
+ rect.left = __crop->left;
+ yskip = mt9p031_skip_for_scale(&rect.height, height, 8,
+ MT9P031_WINDOW_HEIGHT_MAX);
+ if (rect.height + __crop->top > MT9P031_WINDOW_HEIGHT_MAX)
+ rect.top = (MT9P031_WINDOW_HEIGHT_MAX - rect.height) / 2;
+ else
+ rect.top = __crop->top;
+
+ dev_dbg(mt9p031->subdev.v4l2_dev->dev, "%s(%ux%u : %u)\n", __func__,
+ width, height, format->which);
+ if (__crop)
+ *__crop = rect;
+
+ __format = mt9p031_get_pad_format(mt9p031, fh, format->pad,
+ format->which);
+ __format->width = width;
+ __format->height = height;
+ format->format = *__format;
+
+ mt9p031->xskip = xskip;
+ mt9p031->yskip = yskip;
+ mt9p031->rect = *__crop;
+ return 0;
+}
+
+static int mt9p031_pll_enable(struct i2c_client *client)
+{
+ struct mt9p031 *mt9p031 = to_mt9p031(client);
+ int ret;
+
+ ret = reg_write(client, MT9P031_PLL_CONTROL, MT9P031_PLL_CONTROL_PWRON);
+ if (ret < 0)
+ return ret;
+
+ /* Always set the maximum frequency allowed by VDD_IO */
+ if (mt9p031->pdata->vdd_io == MT9P031_VDD_IO_2V8) {
+ ret = reg_write(client, MT9P031_PLL_CONFIG_1,
+ MT9P031_PLL_CONFIG_1_M_96MHZ |
+ MT9P031_PLL_CONFIG_1_N_96MHZ);
+ if (ret < 0)
+ return ret;
+ ret = reg_write(client, MT9P031_PLL_CONFIG_2,
+ MT9P031_PLL_CONFIG_2_P1_96MHZ);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = reg_write(client, MT9P031_PLL_CONFIG_1,
+ MT9P031_PLL_CONFIG_1_M_48MHZ |
+ MT9P031_PLL_CONFIG_1_N_48MHZ);
+ if (ret < 0)
+ return ret;
+ ret = reg_write(client, MT9P031_PLL_CONFIG_2,
+ MT9P031_PLL_CONFIG_2_P1_48MHZ);
+ if (ret < 0)
+ return ret;
+ }
+ mdelay(1);
+ ret = reg_write(client, MT9P031_PLL_CONTROL,
+ MT9P031_PLL_CONTROL_PWRON |
+ MT9P031_PLL_CONTROL_USEPLL);
+ mdelay(1);
+ return ret;
+}
+
+static inline int mt9p031_pll_disable(struct i2c_client *client)
+{
+ return reg_write(client, MT9P031_PLL_CONTROL,
+ MT9P031_PLL_CONTROL_PWROFF);
+}
+
+static int mt9p031_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+ struct v4l2_rect rect = mt9p031->rect;
+ u16 xskip = mt9p031->xskip;
+ u16 yskip = mt9p031->yskip;
+ int ret;
+
+ if (enable) {
+ ret = mt9p031_set_params(client, &rect, xskip, yskip);
+ if (ret < 0)
+ return ret;
+ /* Switch to master "normal" mode */
+ ret = mt9p031_set_output_control(mt9p031, 0,
+ MT9P031_OUTPUT_CONTROL_CEN);
+ if (ret < 0)
+ return ret;
+ ret = mt9p031_pll_enable(client);
+ } else {
+ /* Stop sensor readout */
+ ret = mt9p031_set_output_control(mt9p031,
+ MT9P031_OUTPUT_CONTROL_CEN, 0);
+ if (ret < 0)
+ return ret;
+ ret = mt9p031_pll_disable(client);
+ }
+ return ret;
+}
+
+static int mt9p031_video_probe(struct i2c_client *client)
+{
+ s32 data;
+
+ /* Read out the chip version register */
+ data = reg_read(client, MT9P031_CHIP_VERSION);
+ if (data != MT9P031_CHIP_VERSION_VALUE) {
+ dev_err(&client->dev,
+ "No MT9P031 chip detected, register read %x\n", data);
+ return -ENODEV;
+ }
+
+ dev_info(&client->dev, "Detected a MT9P031 chip ID %x\n", data);
+
+ return 0;
+}
+
+static int mt9p031_set_power(struct v4l2_subdev *sd, int on)
+{
+ struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev);
+ int ret = 0;
+
+ mutex_lock(&mt9p031->power_lock);
+
+ /*
+ * If the power count is modified from 0 to != 0 or from != 0 to 0,
+ * update the power state.
+ */
+ if (mt9p031->power_count == !on) {
+ if (on) {
+ ret = mt9p031_power_on(mt9p031);
+ if (ret) {
+ dev_err(mt9p031->subdev.v4l2_dev->dev,
+ "Failed to power on: %d\n", ret);
+ goto out;
+ }
+ } else {
+ mt9p031_power_off(mt9p031);
+ }
+ }
+
+ /* Update the power count. */
+ mt9p031->power_count += on ? 1 : -1;
+ WARN_ON(mt9p031->power_count < 0);
+
+out:
+ mutex_unlock(&mt9p031->power_lock);
+ return ret;
+}
+
+static int mt9p031_registered(struct v4l2_subdev *sd)
+{
+ struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+ int ret;
+
+ ret = mt9p031_set_power(&mt9p031->subdev, 1);
+ if (ret) {
+ dev_err(&client->dev,
+ "Failed to power on device: %d\n", ret);
+ return ret;
+ }
+
+ ret = mt9p031_video_probe(client);
+
+ mt9p031_set_power(&mt9p031->subdev, 0);
+
+ return ret;
+}
+
+static int mt9p031_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct mt9p031 *mt9p031;
+ mt9p031 = container_of(sd, struct mt9p031, subdev);
+
+ mt9p031->rect.width = MT9P031_WINDOW_WIDTH_DEF;
+ mt9p031->rect.height = MT9P031_WINDOW_HEIGHT_DEF;
+ mt9p031->rect.left = MT9P031_COLUMN_START_DEF;
+ mt9p031->rect.top = MT9P031_ROW_START_DEF;
+
+ if (mt9p031->pdata->version == MT9P031_MONOCHROME_VERSION)
+ mt9p031->format.code = V4L2_MBUS_FMT_Y12_1X12;
+ else
+ mt9p031->format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+
+ mt9p031->format.width = MT9P031_WINDOW_WIDTH_DEF;
+ mt9p031->format.height = MT9P031_WINDOW_HEIGHT_DEF;
+ mt9p031->format.field = V4L2_FIELD_NONE;
+ mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+ mt9p031->xskip = 1;
+ mt9p031->yskip = 1;
+ return mt9p031_set_power(sd, 1);
+}
+
+static int mt9p031_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return mt9p031_set_power(sd, 0);
+}
+
+static struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = {
+ .s_power = mt9p031_set_power,
+};
+
+static struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
+ .s_stream = mt9p031_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
+ .enum_mbus_code = mt9p031_enum_mbus_code,
+ .get_fmt = mt9p031_get_format,
+ .set_fmt = mt9p031_set_format,
+ .get_crop = mt9p031_get_crop,
+ .set_crop = mt9p031_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9p031_subdev_ops = {
+ .core = &mt9p031_subdev_core_ops,
+ .video = &mt9p031_subdev_video_ops,
+ .pad = &mt9p031_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
+ .registered = mt9p031_registered,
+ .open = mt9p031_open,
+ .close = mt9p031_close,
+};
+
+static int mt9p031_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ int ret;
+ struct mt9p031 *mt9p031;
+ struct mt9p031_platform_data *pdata = client->dev.platform_data;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9p031 = kzalloc(sizeof(struct mt9p031), GFP_KERNEL);
+ if (!mt9p031)
+ return -ENOMEM;
+
+ mutex_init(&mt9p031->power_lock);
+ v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);
+ mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops;
+
+ mt9p031->pdata = pdata;
+
+ mt9p031->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&mt9p031->subdev.entity, 1, &mt9p031->pad, 0);
+ if (ret)
+ return ret;
+
+ mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ return 0;
+}
+
+static int mt9p031_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev);
+
+ v4l2_device_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ kfree(mt9p031);
+
+ return 0;
+}
+
+static const struct i2c_device_id mt9p031_id[] = {
+ { "mt9p031", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9p031_id);
+
+static struct i2c_driver mt9p031_i2c_driver = {
+ .driver = {
+ .name = "mt9p031",
+ },
+ .probe = mt9p031_probe,
+ .remove = mt9p031_remove,
+ .id_table = mt9p031_id,
+};
+
+static int __init mt9p031_mod_init(void)
+{
+ return i2c_add_driver(&mt9p031_i2c_driver);
+}
+
+static void __exit mt9p031_mod_exit(void)
+{
+ i2c_del_driver(&mt9p031_i2c_driver);
+}
+
+module_init(mt9p031_mod_init);
+module_exit(mt9p031_mod_exit);
+
+MODULE_DESCRIPTION("Aptina MT9P031 Camera driver");
+MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h
new file mode 100644
index 0000000..27b4c75
--- /dev/null
+++ b/include/media/mt9p031.h
@@ -0,0 +1,23 @@
+#ifndef MT9P031_H
+#define MT9P031_H
+
+struct v4l2_subdev;
+
+enum {
+ MT9P031_COLOR_VERSION = 0,
+ MT9P031_MONOCHROME_VERSION = 1,
+};
+
+enum {
+ MT9P031_VDD_IO_1V8 = 0,
+ MT9P031_VDD_IO_2V8 = 1,
+};
+
+struct mt9p031_platform_data {
+ int (*set_xclk)(struct v4l2_subdev *subdev, int hz);
+ int (*reset)(struct v4l2_subdev *subdev, int active);
+ int vdd_io; /* MT9P031_VDD_IO_1V8 or MT9P031_VDD_IO_2V8 */
+ int version; /* MT9P031_COLOR_VERSION or MT9P031_MONOCHROME_VERSION */
+};
+
+#endif
--
1.6.6.1
@@ -1,853 +0,0 @@
From ba65e798c98e9c4d331deb2b51337964336d3f78 Mon Sep 17 00:00:00 2001
From: Detlev Casanova <detlev.casanova@gmail.com>
Date: Sun, 28 Nov 2010 19:07:20 +0100
Subject: [PATCH 2/3] v4l: Add mt9v032 sensor driver
The MT9V032 is a parallel wide VGA sensor from Aptina (formerly Micron)
controlled through I2C.
The driver creates a V4L2 subdevice. It currently supports binning and
cropping, and the gain, auto gain, exposure, auto exposure and test
pattern controls.
Signed-off-by: Detlev Casanova <detlev.casanova@gmail.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
drivers/media/video/Kconfig | 7 +
drivers/media/video/Makefile | 1 +
drivers/media/video/mt9v032.c | 773 +++++++++++++++++++++++++++++++++++++++++
include/media/mt9v032.h | 12 +
4 files changed, 793 insertions(+), 0 deletions(-)
create mode 100644 drivers/media/video/mt9v032.c
create mode 100644 include/media/mt9v032.h
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index cb87e35..3a5bc57 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -344,6 +344,13 @@ config VIDEO_MT9V011
mt0v011 1.3 Mpixel camera. It currently only works with the
em28xx driver.
+config VIDEO_MT9V032
+ tristate "Micron MT9V032 sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Micron
+ MT9V032 752x480 CMOS sensor.
+
config VIDEO_TCM825X
tristate "TCM825x camera sensor support"
depends on I2C && VIDEO_V4L2
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 912b29b..6679c6a 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
+obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c
new file mode 100644
index 0000000..c64e1dc
--- /dev/null
+++ b/drivers/media/video/mt9v032.c
@@ -0,0 +1,773 @@
+/*
+ * Driver for MT9V032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on the MT9M001 driver,
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/mt9v032.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define MT9V032_PIXEL_ARRAY_HEIGHT 492
+#define MT9V032_PIXEL_ARRAY_WIDTH 782
+
+#define MT9V032_CHIP_VERSION 0x00
+#define MT9V032_CHIP_ID_REV1 0x1311
+#define MT9V032_CHIP_ID_REV3 0x1313
+#define MT9V032_COLUMN_START 0x01
+#define MT9V032_COLUMN_START_MIN 1
+#define MT9V032_COLUMN_START_DEF 1
+#define MT9V032_COLUMN_START_MAX 752
+#define MT9V032_ROW_START 0x02
+#define MT9V032_ROW_START_MIN 4
+#define MT9V032_ROW_START_DEF 5
+#define MT9V032_ROW_START_MAX 482
+#define MT9V032_WINDOW_HEIGHT 0x03
+#define MT9V032_WINDOW_HEIGHT_MIN 1
+#define MT9V032_WINDOW_HEIGHT_DEF 480
+#define MT9V032_WINDOW_HEIGHT_MAX 480
+#define MT9V032_WINDOW_WIDTH 0x04
+#define MT9V032_WINDOW_WIDTH_MIN 1
+#define MT9V032_WINDOW_WIDTH_DEF 752
+#define MT9V032_WINDOW_WIDTH_MAX 752
+#define MT9V032_HORIZONTAL_BLANKING 0x05
+#define MT9V032_HORIZONTAL_BLANKING_MIN 43
+#define MT9V032_HORIZONTAL_BLANKING_MAX 1023
+#define MT9V032_VERTICAL_BLANKING 0x06
+#define MT9V032_VERTICAL_BLANKING_MIN 4
+#define MT9V032_VERTICAL_BLANKING_MAX 3000
+#define MT9V032_CHIP_CONTROL 0x07
+#define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3)
+#define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7)
+#define MT9V032_CHIP_CONTROL_SEQUENTIAL (1 << 8)
+#define MT9V032_SHUTTER_WIDTH1 0x08
+#define MT9V032_SHUTTER_WIDTH2 0x09
+#define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a
+#define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b
+#define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1
+#define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480
+#define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767
+#define MT9V032_RESET 0x0c
+#define MT9V032_READ_MODE 0x0d
+#define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0)
+#define MT9V032_READ_MODE_ROW_BIN_SHIFT 0
+#define MT9V032_READ_MODE_COLUMN_BIN_MASK (3 << 2)
+#define MT9V032_READ_MODE_COLUMN_BIN_SHIFT 2
+#define MT9V032_READ_MODE_ROW_FLIP (1 << 4)
+#define MT9V032_READ_MODE_COLUMN_FLIP (1 << 5)
+#define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6)
+#define MT9V032_READ_MODE_DARK_ROWS (1 << 7)
+#define MT9V032_PIXEL_OPERATION_MODE 0x0f
+#define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2)
+#define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6)
+#define MT9V032_ANALOG_GAIN 0x35
+#define MT9V032_ANALOG_GAIN_MIN 16
+#define MT9V032_ANALOG_GAIN_DEF 16
+#define MT9V032_ANALOG_GAIN_MAX 64
+#define MT9V032_MAX_ANALOG_GAIN 0x36
+#define MT9V032_MAX_ANALOG_GAIN_MAX 127
+#define MT9V032_FRAME_DARK_AVERAGE 0x42
+#define MT9V032_DARK_AVG_THRESH 0x46
+#define MT9V032_DARK_AVG_LOW_THRESH_MASK (255 << 0)
+#define MT9V032_DARK_AVG_LOW_THRESH_SHIFT 0
+#define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8)
+#define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8
+#define MT9V032_ROW_NOISE_CORR_CONTROL 0x70
+#define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5)
+#define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7)
+#define MT9V032_PIXEL_CLOCK 0x74
+#define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0)
+#define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1)
+#define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2)
+#define MT9V032_PIXEL_CLOCK_CONT_LINE (1 << 3)
+#define MT9V032_PIXEL_CLOCK_INV_PXL_CLK (1 << 4)
+#define MT9V032_TEST_PATTERN 0x7f
+#define MT9V032_TEST_PATTERN_DATA_MASK (1023 << 0)
+#define MT9V032_TEST_PATTERN_DATA_SHIFT 0
+#define MT9V032_TEST_PATTERN_USE_DATA (1 << 10)
+#define MT9V032_TEST_PATTERN_GRAY_MASK (3 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_NONE (0 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_VERTICAL (1 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_HORIZONTAL (2 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11)
+#define MT9V032_TEST_PATTERN_ENABLE (1 << 13)
+#define MT9V032_TEST_PATTERN_FLIP (1 << 14)
+#define MT9V032_AEC_AGC_ENABLE 0xaf
+#define MT9V032_AEC_ENABLE (1 << 0)
+#define MT9V032_AGC_ENABLE (1 << 1)
+#define MT9V032_THERMAL_INFO 0xc1
+
+struct mt9v032 {
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_rect crop;
+
+ struct v4l2_ctrl_handler ctrls;
+
+ struct mutex power_lock;
+ int power_count;
+
+ struct mt9v032_platform_data *pdata;
+ u16 chip_control;
+ u16 aec_agc;
+};
+
+static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct mt9v032, subdev);
+}
+
+static int mt9v032_read(struct i2c_client *client, const u8 reg)
+{
+ s32 data = i2c_smbus_read_word_data(client, reg);
+ dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
+ swab16(data), reg);
+ return data < 0 ? data : swab16(data);
+}
+
+static int mt9v032_write(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
+ data, reg);
+ return i2c_smbus_write_word_data(client, reg, swab16(data));
+}
+
+static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ u16 value = (mt9v032->chip_control & ~clear) | set;
+ int ret;
+
+ ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value);
+ if (ret < 0)
+ return ret;
+
+ mt9v032->chip_control = value;
+ return 0;
+}
+
+static int
+mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ u16 value = mt9v032->aec_agc;
+ int ret;
+
+ if (enable)
+ value |= which;
+ else
+ value &= ~which;
+
+ ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value);
+ if (ret < 0)
+ return ret;
+
+ mt9v032->aec_agc = value;
+ return 0;
+}
+
+static int mt9v032_power_on(struct mt9v032 *mt9v032)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ int ret;
+
+ if (mt9v032->pdata->set_clock) {
+ mt9v032->pdata->set_clock(&mt9v032->subdev, 25000000);
+ udelay(1);
+ }
+
+ /* Reset the chip and stop data read out */
+ ret = mt9v032_write(client, MT9V032_RESET, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_RESET, 0);
+ if (ret < 0)
+ return ret;
+
+ return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0);
+}
+
+static void mt9v032_power_off(struct mt9v032 *mt9v032)
+{
+ if (mt9v032->pdata->set_clock)
+ mt9v032->pdata->set_clock(&mt9v032->subdev, 0);
+}
+
+static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ int ret;
+
+ if (!on) {
+ mt9v032_power_off(mt9v032);
+ return 0;
+ }
+
+ ret = mt9v032_power_on(mt9v032);
+ if (ret < 0)
+ return ret;
+
+ /* Configure the pixel clock polarity */
+ if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
+ ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK,
+ MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Disable the noise correction algorithm and restore the controls. */
+ ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
+ if (ret < 0)
+ return ret;
+
+ return v4l2_ctrl_handler_setup(&mt9v032->ctrls);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(fh, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &mt9v032->format;
+ default:
+ return NULL;
+ }
+}
+
+static struct v4l2_rect *
+__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(fh, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &mt9v032->crop;
+ default:
+ return NULL;
+ }
+}
+
+static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
+ | MT9V032_CHIP_CONTROL_DOUT_ENABLE
+ | MT9V032_CHIP_CONTROL_SEQUENTIAL;
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ struct v4l2_mbus_framefmt *format = &mt9v032->format;
+ struct v4l2_rect *crop = &mt9v032->crop;
+ unsigned int hratio;
+ unsigned int vratio;
+ int ret;
+
+ if (!enable)
+ return mt9v032_set_chip_control(mt9v032, mode, 0);
+
+ /* Configure the window size and row/column bin */
+ hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
+ vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
+
+ ret = mt9v032_write(client, MT9V032_READ_MODE,
+ (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT |
+ (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_ROW_START, crop->top);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING,
+ max(43, 660 - crop->width));
+ if (ret < 0)
+ return ret;
+
+ /* Switch to master "normal" mode */
+ return mt9v032_set_chip_control(mt9v032, 0, mode);
+}
+
+static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ return 0;
+}
+
+static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+ return -EINVAL;
+
+ fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index;
+ fse->max_width = fse->min_width;
+ fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static int mt9v032_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+ format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ format->which);
+ return 0;
+}
+
+static int mt9v032_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ struct v4l2_mbus_framefmt *__format;
+ struct v4l2_rect *__crop;
+ unsigned int width;
+ unsigned int height;
+ unsigned int hratio;
+ unsigned int vratio;
+
+ __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad,
+ format->which);
+
+ /* Clamp the width and height to avoid dividing by zero. */
+ width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+ max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN),
+ __crop->width);
+ height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+ max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN),
+ __crop->height);
+
+ hratio = DIV_ROUND_CLOSEST(__crop->width, width);
+ vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+
+ __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ format->which);
+ __format->width = __crop->width / hratio;
+ __format->height = __crop->height / vratio;
+
+ format->format = *__format;
+
+ return 0;
+}
+
+static int mt9v032_get_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+ crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad,
+ crop->which);
+ return 0;
+}
+
+static int mt9v032_set_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ struct v4l2_mbus_framefmt *__format;
+ struct v4l2_rect *__crop;
+ struct v4l2_rect rect;
+
+ /* Clamp the crop rectangle boundaries and align them to a non multiple
+ * of 2 pixels to ensure a GRBG Bayer pattern.
+ */
+ rect.left = clamp(ALIGN(crop->rect.left + 1, 2) - 1,
+ MT9V032_COLUMN_START_MIN,
+ MT9V032_COLUMN_START_MAX);
+ rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1,
+ MT9V032_ROW_START_MIN,
+ MT9V032_ROW_START_MAX);
+ rect.width = clamp(ALIGN(crop->rect.width, 2),
+ MT9V032_WINDOW_WIDTH_MIN,
+ MT9V032_WINDOW_WIDTH_MAX);
+ rect.height = clamp(ALIGN(crop->rect.height, 2),
+ MT9V032_WINDOW_HEIGHT_MIN,
+ MT9V032_WINDOW_HEIGHT_MAX);
+
+ rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
+ rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
+
+ __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
+
+ if (rect.width != __crop->width || rect.height != __crop->height) {
+ /* Reset the output image size if the crop rectangle size has
+ * been modified.
+ */
+ __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad,
+ crop->which);
+ __format->width = rect.width;
+ __format->height = rect.height;
+ }
+
+ *__crop = rect;
+ crop->rect = rect;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001)
+
+static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9v032 *mt9v032 =
+ container_of(ctrl->handler, struct mt9v032, ctrls);
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ u16 data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ return mt9v032_update_aec_agc(mt9v032, MT9V032_AGC_ENABLE,
+ ctrl->val);
+
+ case V4L2_CID_GAIN:
+ return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val);
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
+ ctrl->val);
+
+ case V4L2_CID_EXPOSURE:
+ return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
+ ctrl->val);
+
+ case V4L2_CID_TEST_PATTERN:
+ switch (ctrl->val) {
+ case 0:
+ data = 0;
+ break;
+ case 1:
+ data = MT9V032_TEST_PATTERN_GRAY_VERTICAL
+ | MT9V032_TEST_PATTERN_ENABLE;
+ break;
+ case 2:
+ data = MT9V032_TEST_PATTERN_GRAY_HORIZONTAL
+ | MT9V032_TEST_PATTERN_ENABLE;
+ break;
+ case 3:
+ data = MT9V032_TEST_PATTERN_GRAY_DIAGONAL
+ | MT9V032_TEST_PATTERN_ENABLE;
+ break;
+ default:
+ data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT)
+ | MT9V032_TEST_PATTERN_USE_DATA
+ | MT9V032_TEST_PATTERN_ENABLE
+ | MT9V032_TEST_PATTERN_FLIP;
+ break;
+ }
+
+ return mt9v032_write(client, MT9V032_TEST_PATTERN, data);
+ }
+
+ return 0;
+}
+
+static struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
+ .s_ctrl = mt9v032_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config mt9v032_ctrls[] = {
+ {
+ .ops = &mt9v032_ctrl_ops,
+ .id = V4L2_CID_TEST_PATTERN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Test pattern",
+ .min = 0,
+ .max = 1023,
+ .step = 1,
+ .def = 0,
+ .flags = 0,
+ }
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int mt9v032_set_power(struct v4l2_subdev *subdev, int on)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ int ret = 0;
+
+ mutex_lock(&mt9v032->power_lock);
+
+ /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+ * update the power state.
+ */
+ if (mt9v032->power_count == !on) {
+ ret = __mt9v032_set_power(mt9v032, !!on);
+ if (ret < 0)
+ goto done;
+ }
+
+ /* Update the power count. */
+ mt9v032->power_count += on ? 1 : -1;
+ WARN_ON(mt9v032->power_count < 0);
+
+done:
+ mutex_unlock(&mt9v032->power_lock);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int mt9v032_registered(struct v4l2_subdev *subdev)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ s32 data;
+ int ret;
+
+ dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
+ client->addr);
+
+ ret = mt9v032_power_on(mt9v032);
+ if (ret < 0) {
+ dev_err(&client->dev, "MT9V032 power up failed\n");
+ return ret;
+ }
+
+ /* Read and check the sensor version */
+ data = mt9v032_read(client, MT9V032_CHIP_VERSION);
+ if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) {
+ dev_err(&client->dev, "MT9V032 not detected, wrong version "
+ "0x%04x\n", data);
+ return -ENODEV;
+ }
+
+ mt9v032_power_off(mt9v032);
+
+ dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n",
+ client->addr);
+
+ return ret;
+}
+
+static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ crop = v4l2_subdev_get_try_crop(fh, 0);
+ crop->left = MT9V032_COLUMN_START_DEF;
+ crop->top = MT9V032_ROW_START_DEF;
+ crop->width = MT9V032_WINDOW_WIDTH_DEF;
+ crop->height = MT9V032_WINDOW_HEIGHT_DEF;
+
+ format = v4l2_subdev_get_try_format(fh, 0);
+ format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format->width = MT9V032_WINDOW_WIDTH_DEF;
+ format->height = MT9V032_WINDOW_HEIGHT_DEF;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return mt9v032_set_power(subdev, 1);
+}
+
+static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return mt9v032_set_power(subdev, 0);
+}
+
+static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = {
+ .s_power = mt9v032_set_power,
+};
+
+static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = {
+ .s_stream = mt9v032_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
+ .enum_mbus_code = mt9v032_enum_mbus_code,
+ .enum_frame_size = mt9v032_enum_frame_size,
+ .get_fmt = mt9v032_get_format,
+ .set_fmt = mt9v032_set_format,
+ .get_crop = mt9v032_get_crop,
+ .set_crop = mt9v032_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9v032_subdev_ops = {
+ .core = &mt9v032_subdev_core_ops,
+ .video = &mt9v032_subdev_video_ops,
+ .pad = &mt9v032_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
+ .registered = mt9v032_registered,
+ .open = mt9v032_open,
+ .close = mt9v032_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9v032_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct mt9v032 *mt9v032;
+ unsigned int i;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&client->adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL);
+ if (!mt9v032)
+ return -ENOMEM;
+
+ mutex_init(&mt9v032->power_lock);
+ mt9v032->pdata = client->dev.platform_data;
+
+ v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 4);
+
+ v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_GAIN, MT9V032_ANALOG_GAIN_MIN,
+ MT9V032_ANALOG_GAIN_MAX, 1, MT9V032_ANALOG_GAIN_DEF);
+ v4l2_ctrl_new_std_menu(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
+ V4L2_EXPOSURE_AUTO);
+ v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
+ MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1,
+ MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
+
+ for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i)
+ v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL);
+
+ mt9v032->subdev.ctrl_handler = &mt9v032->ctrls;
+
+ if (mt9v032->ctrls.error)
+ printk(KERN_INFO "%s: control initialization error %d\n",
+ __func__, mt9v032->ctrls.error);
+
+ mt9v032->crop.left = MT9V032_COLUMN_START_DEF;
+ mt9v032->crop.top = MT9V032_ROW_START_DEF;
+ mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF;
+ mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
+
+ mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
+ mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
+ mt9v032->format.field = V4L2_FIELD_NONE;
+ mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+ mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
+
+ v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops);
+ mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops;
+ mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
+ if (ret < 0)
+ kfree(mt9v032);
+
+ return ret;
+}
+
+static int mt9v032_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+ v4l2_device_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+ kfree(mt9v032);
+ return 0;
+}
+
+static const struct i2c_device_id mt9v032_id[] = {
+ { "mt9v032", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v032_id);
+
+static struct i2c_driver mt9v032_driver = {
+ .driver = {
+ .name = "mt9v032",
+ },
+ .probe = mt9v032_probe,
+ .remove = mt9v032_remove,
+ .id_table = mt9v032_id,
+};
+
+static int __init mt9v032_init(void)
+{
+ return i2c_add_driver(&mt9v032_driver);
+}
+
+static void __exit mt9v032_exit(void)
+{
+ i2c_del_driver(&mt9v032_driver);
+}
+
+module_init(mt9v032_init);
+module_exit(mt9v032_exit);
+
+MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/media/mt9v032.h b/include/media/mt9v032.h
new file mode 100644
index 0000000..5e27f9b
--- /dev/null
+++ b/include/media/mt9v032.h
@@ -0,0 +1,12 @@
+#ifndef _MEDIA_MT9V032_H
+#define _MEDIA_MT9V032_H
+
+struct v4l2_subdev;
+
+struct mt9v032_platform_data {
+ unsigned int clk_pol:1;
+
+ void (*set_clock)(struct v4l2_subdev *subdev, unsigned int rate);
+};
+
+#endif
--
1.6.6.1
@@ -1,162 +0,0 @@
From f662a8a2b9794121568903f5cc969e50eb151892 Mon Sep 17 00:00:00 2001
From: Javier Martin <javier.martin@vista-silicon.com>
Date: Mon, 30 May 2011 10:37:17 +0200
Subject: [PATCH 3/3] Add support for mt9p031 (LI-5M03 module) in Beagleboard xM.
Since isp clocks have not been exposed yet, this patch
includes a temporal solution for testing mt9p031 driver
in Beagleboard xM.
Signed-off-by: Javier Martin <javier.martin@vista-silicon.com>
---
arch/arm/mach-omap2/Makefile | 1 +
arch/arm/mach-omap2/board-omap3beagle-camera.c | 95 ++++++++++++++++++++++++
arch/arm/mach-omap2/board-omap3beagle.c | 5 +
3 files changed, 101 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-omap2/board-omap3beagle-camera.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 512b152..05cd983 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -179,6 +179,7 @@ obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o \
hsmmc.o
obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o
obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o \
+ board-omap3beagle-camera.o \
hsmmc.o
obj-$(CONFIG_MACH_DEVKIT8000) += board-devkit8000.o \
hsmmc.o
diff --git a/arch/arm/mach-omap2/board-omap3beagle-camera.c b/arch/arm/mach-omap2/board-omap3beagle-camera.c
new file mode 100644
index 0000000..2632557
--- /dev/null
+++ b/arch/arm/mach-omap2/board-omap3beagle-camera.c
@@ -0,0 +1,95 @@
+#include <linux/gpio.h>
+#include <linux/regulator/machine.h>
+
+#include <plat/i2c.h>
+
+#include <media/mt9p031.h>
+#include <asm/mach-types.h>
+#include "devices.h"
+#include "../../../drivers/media/video/omap3isp/isp.h"
+
+#define MT9P031_RESET_GPIO 98
+#define MT9P031_XCLK ISP_XCLK_A
+
+static struct regulator *reg_1v8, *reg_2v8;
+
+static int beagle_cam_set_xclk(struct v4l2_subdev *subdev, int hz)
+{
+ struct isp_device *isp = v4l2_dev_to_isp_device(subdev->v4l2_dev);
+ int ret;
+
+ ret = isp->platform_cb.set_xclk(isp, hz, MT9P031_XCLK);
+ return 0;
+}
+
+static int beagle_cam_reset(struct v4l2_subdev *subdev, int active)
+{
+ /* Set RESET_BAR to !active */
+ gpio_set_value(MT9P031_RESET_GPIO, !active);
+
+ return 0;
+}
+
+static struct mt9p031_platform_data beagle_mt9p031_platform_data = {
+ .set_xclk = beagle_cam_set_xclk,
+ .reset = beagle_cam_reset,
+ .vdd_io = MT9P031_VDD_IO_1V8,
+ .version = MT9P031_COLOR_VERSION,
+};
+
+static struct i2c_board_info mt9p031_camera_i2c_device = {
+ I2C_BOARD_INFO("mt9p031", 0x48),
+ .platform_data = &beagle_mt9p031_platform_data,
+};
+
+static struct isp_subdev_i2c_board_info mt9p031_camera_subdevs[] = {
+ {
+ .board_info = &mt9p031_camera_i2c_device,
+ .i2c_adapter_id = 2,
+ },
+ { NULL, 0, },
+};
+
+static struct isp_v4l2_subdevs_group beagle_camera_subdevs[] = {
+ {
+ .subdevs = mt9p031_camera_subdevs,
+ .interface = ISP_INTERFACE_PARALLEL,
+ .bus = {
+ .parallel = {
+ .data_lane_shift = 0,
+ .clk_pol = 1,
+ .bridge = ISPCTRL_PAR_BRIDGE_DISABLE,
+ }
+ },
+ },
+ { },
+};
+
+static struct isp_platform_data beagle_isp_platform_data = {
+ .subdevs = beagle_camera_subdevs,
+};
+
+static int __init beagle_camera_init(void)
+{
+ if (!machine_is_omap3_beagle() || !cpu_is_omap3630())
+ return 0;
+
+ reg_1v8 = regulator_get(NULL, "cam_1v8");
+ if (IS_ERR(reg_1v8))
+ pr_err("%s: cannot get cam_1v8 regulator\n", __func__);
+ else
+ regulator_enable(reg_1v8);
+
+ reg_2v8 = regulator_get(NULL, "cam_2v8");
+ if (IS_ERR(reg_2v8))
+ pr_err("%s: cannot get cam_2v8 regulator\n", __func__);
+ else
+ regulator_enable(reg_2v8);
+
+ omap_register_i2c_bus(2, 100, NULL, 0);
+ gpio_request(MT9P031_RESET_GPIO, "cam_rst");
+ gpio_direction_output(MT9P031_RESET_GPIO, 0);
+ omap3_init_camera(&beagle_isp_platform_data);
+ return 0;
+}
+late_initcall(beagle_camera_init);
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 221bfda..dd6e31f 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -25,12 +25,16 @@
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/opp.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/videodev2.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/mmc/host.h>
+#include <linux/gpio.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
@@ -48,6 +52,7 @@
#include <plat/nand.h>
#include <plat/usb.h>
#include <plat/omap_device.h>
+#include <plat/i2c.h>
#include "mux.h"
#include "hsmmc.h"
--
1.6.6.1
@@ -1,67 +0,0 @@
From 46be90d202c36db19e27c2991cbff401c6c3ee81 Mon Sep 17 00:00:00 2001
From: Keshava Munegowda <Keshava_mgowda@ti.com>
Date: Mon, 16 May 2011 14:24:58 +0530
Subject: [PATCH 01/13] mfd: Fix omap usbhs crash when rmmoding ehci or ohci
The disabling of clocks and freeing GPIO are changed
to fix the occurrence of the crash of rmmod of ehci and ohci
drivers. The GPIOs should be freed after the spin locks are
unlocked.
Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Cc: stable@kernel.org
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/omap-usb-host.c | 27 +++++++++++++++++++--------
1 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 3ab9ffa..55c5d47 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -994,22 +994,33 @@ static void usbhs_disable(struct device *dev)
dev_dbg(dev, "operation timed out\n");
}
- if (pdata->ehci_data->phy_reset) {
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
- gpio_free(pdata->ehci_data->reset_gpio_port[0]);
-
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
- gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+ if (is_omap_usbhs_rev2(omap)) {
+ if (is_ehci_tll_mode(pdata->port_mode[0]))
+ clk_enable(omap->usbtll_p1_fck);
+ if (is_ehci_tll_mode(pdata->port_mode[1]))
+ clk_enable(omap->usbtll_p2_fck);
+ clk_disable(omap->utmi_p2_fck);
+ clk_disable(omap->utmi_p1_fck);
}
- clk_disable(omap->utmi_p2_fck);
- clk_disable(omap->utmi_p1_fck);
clk_disable(omap->usbtll_ick);
clk_disable(omap->usbtll_fck);
clk_disable(omap->usbhost_fs_fck);
clk_disable(omap->usbhost_hs_fck);
clk_disable(omap->usbhost_ick);
+ /* The gpio_free migh sleep; so unlock the spinlock */
+ spin_unlock_irqrestore(&omap->lock, flags);
+
+ if (pdata->ehci_data->phy_reset) {
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+ gpio_free(pdata->ehci_data->reset_gpio_port[0]);
+
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+ gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+ }
+ return;
+
end_disble:
spin_unlock_irqrestore(&omap->lock, flags);
}
--
1.6.6.1
@@ -1,50 +0,0 @@
From 89a903aca8fda3dcf1a6f9a424247e772afdd44e Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@gmail.com>
Date: Sat, 14 May 2011 14:15:36 +0800
Subject: [PATCH 02/13] mfd: Fix omap_usbhs_alloc_children error handling
1. Return proper error if omap_usbhs_alloc_child fails
2. In the case of goto err_ehci, we should call platform_device_unregister(ehci)
instead of platform_device_put(ehci) because we have already added the
platform device to device hierarchy.
Signed-off-by: Axel Lin <axel.lin@gmail.com>
Signed-off-by: Axel Lin <axel.lin@gmail.com>
Tested-by: Keshava Munegowda <keshava_mgowda@ti.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/omap-usb-host.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 55c5d47..1717144 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -281,6 +281,7 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
if (!ehci) {
dev_err(dev, "omap_usbhs_alloc_child failed\n");
+ ret = -ENOMEM;
goto err_end;
}
@@ -304,13 +305,14 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
sizeof(*ohci_data), dev);
if (!ohci) {
dev_err(dev, "omap_usbhs_alloc_child failed\n");
+ ret = -ENOMEM;
goto err_ehci;
}
return 0;
err_ehci:
- platform_device_put(ehci);
+ platform_device_unregister(ehci);
err_end:
return ret;
--
1.6.6.1
@@ -1,245 +0,0 @@
From edc881f9c4897fab11542cd5c36a33b288f702be Mon Sep 17 00:00:00 2001
From: Keshava Munegowda <Keshava_mgowda@ti.com>
Date: Sun, 22 May 2011 22:51:26 +0200
Subject: [PATCH 03/13] mfd: Add omap-usbhs runtime PM support
The usbhs core driver does not enable/disable the interface and
functional clocks; These clocks are handled by hwmod and runtime pm,
hence insted of the clock enable/disable, the runtime pm APIS are
used. however,the port clocks and tll clocks are handled
by the usbhs core.
Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/omap-usb-host.c | 131 +++----------------------------------------
1 files changed, 9 insertions(+), 122 deletions(-)
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 1717144..8552195 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <plat/usb.h>
+#include <linux/pm_runtime.h>
#define USBHS_DRIVER_NAME "usbhs-omap"
#define OMAP_EHCI_DEVICE "ehci-omap"
@@ -146,9 +147,6 @@
struct usbhs_hcd_omap {
- struct clk *usbhost_ick;
- struct clk *usbhost_hs_fck;
- struct clk *usbhost_fs_fck;
struct clk *xclk60mhsp1_ck;
struct clk *xclk60mhsp2_ck;
struct clk *utmi_p1_fck;
@@ -158,8 +156,6 @@ struct usbhs_hcd_omap {
struct clk *usbhost_p2_fck;
struct clk *usbtll_p2_fck;
struct clk *init_60m_fclk;
- struct clk *usbtll_fck;
- struct clk *usbtll_ick;
void __iomem *uhh_base;
void __iomem *tll_base;
@@ -353,46 +349,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
omap->platdata.ehci_data = pdata->ehci_data;
omap->platdata.ohci_data = pdata->ohci_data;
- omap->usbhost_ick = clk_get(dev, "usbhost_ick");
- if (IS_ERR(omap->usbhost_ick)) {
- ret = PTR_ERR(omap->usbhost_ick);
- dev_err(dev, "usbhost_ick failed error:%d\n", ret);
- goto err_end;
- }
-
- omap->usbhost_hs_fck = clk_get(dev, "hs_fck");
- if (IS_ERR(omap->usbhost_hs_fck)) {
- ret = PTR_ERR(omap->usbhost_hs_fck);
- dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret);
- goto err_usbhost_ick;
- }
-
- omap->usbhost_fs_fck = clk_get(dev, "fs_fck");
- if (IS_ERR(omap->usbhost_fs_fck)) {
- ret = PTR_ERR(omap->usbhost_fs_fck);
- dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret);
- goto err_usbhost_hs_fck;
- }
-
- omap->usbtll_fck = clk_get(dev, "usbtll_fck");
- if (IS_ERR(omap->usbtll_fck)) {
- ret = PTR_ERR(omap->usbtll_fck);
- dev_err(dev, "usbtll_fck failed error:%d\n", ret);
- goto err_usbhost_fs_fck;
- }
-
- omap->usbtll_ick = clk_get(dev, "usbtll_ick");
- if (IS_ERR(omap->usbtll_ick)) {
- ret = PTR_ERR(omap->usbtll_ick);
- dev_err(dev, "usbtll_ick failed error:%d\n", ret);
- goto err_usbtll_fck;
- }
+ pm_runtime_enable(&pdev->dev);
omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
if (IS_ERR(omap->utmi_p1_fck)) {
ret = PTR_ERR(omap->utmi_p1_fck);
dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
- goto err_usbtll_ick;
+ goto err_end;
}
omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
@@ -522,22 +485,8 @@ err_xclk60mhsp1_ck:
err_utmi_p1_fck:
clk_put(omap->utmi_p1_fck);
-err_usbtll_ick:
- clk_put(omap->usbtll_ick);
-
-err_usbtll_fck:
- clk_put(omap->usbtll_fck);
-
-err_usbhost_fs_fck:
- clk_put(omap->usbhost_fs_fck);
-
-err_usbhost_hs_fck:
- clk_put(omap->usbhost_hs_fck);
-
-err_usbhost_ick:
- clk_put(omap->usbhost_ick);
-
err_end:
+ pm_runtime_disable(&pdev->dev);
kfree(omap);
end_probe:
@@ -571,11 +520,7 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev)
clk_put(omap->utmi_p2_fck);
clk_put(omap->xclk60mhsp1_ck);
clk_put(omap->utmi_p1_fck);
- clk_put(omap->usbtll_ick);
- clk_put(omap->usbtll_fck);
- clk_put(omap->usbhost_fs_fck);
- clk_put(omap->usbhost_hs_fck);
- clk_put(omap->usbhost_ick);
+ pm_runtime_disable(&pdev->dev);
kfree(omap);
return 0;
@@ -695,7 +640,6 @@ static int usbhs_enable(struct device *dev)
struct usbhs_omap_platform_data *pdata = &omap->platdata;
unsigned long flags = 0;
int ret = 0;
- unsigned long timeout;
unsigned reg;
dev_dbg(dev, "starting TI HSUSB Controller\n");
@@ -708,11 +652,7 @@ static int usbhs_enable(struct device *dev)
if (omap->count > 0)
goto end_count;
- clk_enable(omap->usbhost_ick);
- clk_enable(omap->usbhost_hs_fck);
- clk_enable(omap->usbhost_fs_fck);
- clk_enable(omap->usbtll_fck);
- clk_enable(omap->usbtll_ick);
+ pm_runtime_get_sync(dev);
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
@@ -736,50 +676,6 @@ static int usbhs_enable(struct device *dev)
omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
- /* perform TLL soft reset, and wait until reset is complete */
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
- OMAP_USBTLL_SYSCONFIG_SOFTRESET);
-
- /* Wait for TLL reset to complete */
- timeout = jiffies + msecs_to_jiffies(1000);
- while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
- & OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
- cpu_relax();
-
- if (time_after(jiffies, timeout)) {
- dev_dbg(dev, "operation timed out\n");
- ret = -EINVAL;
- goto err_tll;
- }
- }
-
- dev_dbg(dev, "TLL RESET DONE\n");
-
- /* (1<<3) = no idle mode only for initial debugging */
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
- OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
- OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
- OMAP_USBTLL_SYSCONFIG_AUTOIDLE);
-
- /* Put UHH in NoIdle/NoStandby mode */
- reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
- if (is_omap_usbhs_rev1(omap)) {
- reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
- | OMAP_UHH_SYSCONFIG_SIDLEMODE
- | OMAP_UHH_SYSCONFIG_CACTIVITY
- | OMAP_UHH_SYSCONFIG_MIDLEMODE);
- reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
-
-
- } else if (is_omap_usbhs_rev2(omap)) {
- reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
- reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
- reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
- reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
- }
-
- usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
-
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
/* setup ULPI bypass and burst configurations */
reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
@@ -919,6 +815,8 @@ end_count:
return 0;
err_tll:
+ pm_runtime_put_sync(dev);
+ spin_unlock_irqrestore(&omap->lock, flags);
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
gpio_free(pdata->ehci_data->reset_gpio_port[0]);
@@ -926,13 +824,6 @@ err_tll:
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
}
-
- clk_disable(omap->usbtll_ick);
- clk_disable(omap->usbtll_fck);
- clk_disable(omap->usbhost_fs_fck);
- clk_disable(omap->usbhost_hs_fck);
- clk_disable(omap->usbhost_ick);
- spin_unlock_irqrestore(&omap->lock, flags);
return ret;
}
@@ -1005,11 +896,7 @@ static void usbhs_disable(struct device *dev)
clk_disable(omap->utmi_p1_fck);
}
- clk_disable(omap->usbtll_ick);
- clk_disable(omap->usbtll_fck);
- clk_disable(omap->usbhost_fs_fck);
- clk_disable(omap->usbhost_hs_fck);
- clk_disable(omap->usbhost_ick);
+ pm_runtime_put_sync(dev);
/* The gpio_free migh sleep; so unlock the spinlock */
spin_unlock_irqrestore(&omap->lock, flags);
--
1.6.6.1
@@ -1,406 +0,0 @@
From 339b167f6f76707a2d6ae3a7c0b921b8278564af Mon Sep 17 00:00:00 2001
From: Keshava Munegowda <Keshava_mgowda@ti.com>
Date: Wed, 1 Jun 2011 11:02:49 -0700
Subject: [PATCH 04/13] arm: omap: usb: ehci and ohci hwmod structures for omap3 and omap4
Following 2 hwmod strcuture are added:
UHH hwmod of usbhs with uhh base address and
EHCI , OHCI irq and base addresses.
TLL hwmod of usbhs with the TLL base address and irq.
Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
---
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 184 ++++++++++++++++++++++++++++
arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 153 +++++++++++++++++++++++
2 files changed, 337 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 909a84d..fe9a176 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -84,6 +84,8 @@ static struct omap_hwmod omap3xxx_mcbsp4_hwmod;
static struct omap_hwmod omap3xxx_mcbsp5_hwmod;
static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod;
static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod;
+static struct omap_hwmod omap34xx_usb_host_hs_hwmod;
+static struct omap_hwmod omap34xx_usb_tll_hs_hwmod;
/* L3 -> L4_CORE interface */
static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
@@ -3574,6 +3576,185 @@ static struct omap_hwmod omap3xxx_mmc3_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
};
+/*
+ * 'usb_host_hs' class
+ * high-speed multi-port usb host controller
+ */
+static struct omap_hwmod_ocp_if omap34xx_usb_host_hs__l3_main_2 = {
+ .master = &omap34xx_usb_host_hs_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .clk = "core_l3_ick",
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_class_sysconfig omap34xx_usb_host_hs_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap34xx_usb_host_hs_hwmod_class = {
+ .name = "usbhs_uhh",
+ .sysc = &omap34xx_usb_host_hs_sysc,
+};
+
+static struct omap_hwmod_ocp_if *omap34xx_usb_host_hs_masters[] = {
+ &omap34xx_usb_host_hs__l3_main_2,
+};
+
+static struct omap_hwmod_irq_info omap34xx_usb_host_hs_irqs[] = {
+ { .name = "ohci-irq", .irq = 76 },
+ { .name = "ehci-irq", .irq = 77 },
+};
+
+static struct omap_hwmod_addr_space omap34xx_usb_host_hs_addrs[] = {
+ {
+ .name = "uhh",
+ .pa_start = 0x48064000,
+ .pa_end = 0x480643ff,
+ .flags = ADDR_TYPE_RT
+ },
+ {
+ .name = "ohci",
+ .pa_start = 0x48064400,
+ .pa_end = 0x480647FF,
+ .flags = ADDR_MAP_ON_INIT
+ },
+ {
+ .name = "ehci",
+ .pa_start = 0x48064800,
+ .pa_end = 0x48064CFF,
+ .flags = ADDR_MAP_ON_INIT
+ }
+};
+
+static struct omap_hwmod_ocp_if omap34xx_l4_cfg__usb_host_hs = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_usb_host_hs_hwmod,
+ .clk = "l4_ick",
+ .addr = omap34xx_usb_host_hs_addrs,
+ .addr_cnt = ARRAY_SIZE(omap34xx_usb_host_hs_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if omap34xx_f128m_cfg__usb_host_hs = {
+ .clk = "usbhost_120m_fck",
+ .user = OCP_USER_MPU,
+ .flags = OCPIF_SWSUP_IDLE,
+};
+
+static struct omap_hwmod_ocp_if omap34xx_f48m_cfg__usb_host_hs = {
+ .clk = "usbhost_48m_fck",
+ .user = OCP_USER_MPU,
+ .flags = OCPIF_SWSUP_IDLE,
+};
+
+static struct omap_hwmod_ocp_if *omap34xx_usb_host_hs_slaves[] = {
+ &omap34xx_l4_cfg__usb_host_hs,
+ &omap34xx_f128m_cfg__usb_host_hs,
+ &omap34xx_f48m_cfg__usb_host_hs,
+};
+
+static struct omap_hwmod omap34xx_usb_host_hs_hwmod = {
+ .name = "usbhs_uhh",
+ .class = &omap34xx_usb_host_hs_hwmod_class,
+ .mpu_irqs = omap34xx_usb_host_hs_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_usb_host_hs_irqs),
+ .main_clk = "usbhost_ick",
+ .prcm = {
+ .omap2 = {
+ .module_offs = OMAP3430ES2_USBHOST_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = 0,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = 1,
+ .idlest_stdby_bit = 0,
+ },
+ },
+ .slaves = omap34xx_usb_host_hs_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap34xx_usb_host_hs_slaves),
+ .masters = omap34xx_usb_host_hs_masters,
+ .masters_cnt = ARRAY_SIZE(omap34xx_usb_host_hs_masters),
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/*
+ * 'usb_tll_hs' class
+ * usb_tll_hs module is the adapter on the usb_host_hs ports
+ */
+static struct omap_hwmod_class_sysconfig omap34xx_usb_tll_hs_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap34xx_usb_tll_hs_hwmod_class = {
+ .name = "usbhs_tll",
+ .sysc = &omap34xx_usb_tll_hs_sysc,
+};
+
+static struct omap_hwmod_irq_info omap34xx_usb_tll_hs_irqs[] = {
+ { .name = "tll-irq", .irq = 78 },
+};
+
+static struct omap_hwmod_addr_space omap34xx_usb_tll_hs_addrs[] = {
+ {
+ .name = "tll",
+ .pa_start = 0x48062000,
+ .pa_end = 0x48062fff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+static struct omap_hwmod_ocp_if omap34xx_f_cfg__usb_tll_hs = {
+ .clk = "usbtll_fck",
+ .user = OCP_USER_MPU,
+ .flags = OCPIF_SWSUP_IDLE,
+};
+
+static struct omap_hwmod_ocp_if omap34xx_l4_cfg__usb_tll_hs = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_usb_tll_hs_hwmod,
+ .clk = "l4_ick",
+ .addr = omap34xx_usb_tll_hs_addrs,
+ .addr_cnt = ARRAY_SIZE(omap34xx_usb_tll_hs_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if *omap34xx_usb_tll_hs_slaves[] = {
+ &omap34xx_l4_cfg__usb_tll_hs,
+ &omap34xx_f_cfg__usb_tll_hs,
+};
+
+static struct omap_hwmod omap34xx_usb_tll_hs_hwmod = {
+ .name = "usbhs_tll",
+ .class = &omap34xx_usb_tll_hs_hwmod_class,
+ .mpu_irqs = omap34xx_usb_tll_hs_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap34xx_usb_tll_hs_irqs),
+ .main_clk = "usbtll_ick",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 3,
+ .module_bit = 2,
+ .idlest_reg_id = 3,
+ .idlest_idle_bit = 2,
+ },
+ },
+ .slaves = omap34xx_usb_tll_hs_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap34xx_usb_tll_hs_slaves),
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
&omap3xxx_l3_main_hwmod,
&omap3xxx_l4_core_hwmod,
@@ -3656,6 +3837,9 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
/* usbotg for am35x */
&am35xx_usbhsotg_hwmod,
+ &omap34xx_usb_host_hs_hwmod,
+ &omap34xx_usb_tll_hs_hwmod,
+
NULL,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index abc548a..d7112b0 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -66,6 +66,8 @@ static struct omap_hwmod omap44xx_mmc2_hwmod;
static struct omap_hwmod omap44xx_mpu_hwmod;
static struct omap_hwmod omap44xx_mpu_private_hwmod;
static struct omap_hwmod omap44xx_usb_otg_hs_hwmod;
+static struct omap_hwmod omap44xx_usb_host_hs_hwmod;
+static struct omap_hwmod omap44xx_usb_tll_hs_hwmod;
/*
* Interconnects omap_hwmod structures
@@ -5027,6 +5029,155 @@ static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
.omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
};
+/*
+ * 'usb_host_hs' class
+ * high-speed multi-port usb host controller
+ */
+static struct omap_hwmod_ocp_if omap44xx_usb_host_hs__l3_main_2 = {
+ .master = &omap44xx_usb_host_hs_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_class_sysconfig omap44xx_usb_host_hs_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_usb_host_hs_hwmod_class = {
+ .name = "usbhs_uhh",
+ .sysc = &omap44xx_usb_host_hs_sysc,
+};
+
+static struct omap_hwmod_ocp_if *omap44xx_usb_host_hs_masters[] = {
+ &omap44xx_usb_host_hs__l3_main_2,
+};
+
+static struct omap_hwmod_irq_info omap44xx_usb_host_hs_irqs[] = {
+ { .name = "ohci-irq", .irq = 76 + OMAP44XX_IRQ_GIC_START },
+ { .name = "ehci-irq", .irq = 77 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_usb_host_hs_addrs[] = {
+ {
+ .name = "uhh",
+ .pa_start = 0x4a064000,
+ .pa_end = 0x4a0647ff,
+ .flags = ADDR_TYPE_RT
+ },
+ {
+ .name = "ohci",
+ .pa_start = 0x4A064800,
+ .pa_end = 0x4A064BFF,
+ .flags = ADDR_MAP_ON_INIT
+ },
+ {
+ .name = "ehci",
+ .pa_start = 0x4A064C00,
+ .pa_end = 0x4A064FFF,
+ .flags = ADDR_MAP_ON_INIT
+ }
+};
+
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_hs = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_usb_host_hs_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_usb_host_hs_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_usb_host_hs_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if *omap44xx_usb_host_hs_slaves[] = {
+ &omap44xx_l4_cfg__usb_host_hs,
+};
+
+static struct omap_hwmod omap44xx_usb_host_hs_hwmod = {
+ .name = "usbhs_uhh",
+ .class = &omap44xx_usb_host_hs_hwmod_class,
+ .mpu_irqs = omap44xx_usb_host_hs_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_usb_host_hs_irqs),
+ .main_clk = "usb_host_hs_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_usb_host_hs_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_usb_host_hs_slaves),
+ .masters = omap44xx_usb_host_hs_masters,
+ .masters_cnt = ARRAY_SIZE(omap44xx_usb_host_hs_masters),
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'usb_tll_hs' class
+ * usb_tll_hs module is the adapter on the usb_host_hs ports
+ */
+static struct omap_hwmod_class_sysconfig omap44xx_usb_tll_hs_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_usb_tll_hs_hwmod_class = {
+ .name = "usbhs_tll",
+ .sysc = &omap44xx_usb_tll_hs_sysc,
+};
+
+static struct omap_hwmod_irq_info omap44xx_usb_tll_hs_irqs[] = {
+ { .name = "tll-irq", .irq = 78 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_usb_tll_hs_addrs[] = {
+ {
+ .name = "tll",
+ .pa_start = 0x4a062000,
+ .pa_end = 0x4a063fff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_tll_hs = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_usb_tll_hs_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_usb_tll_hs_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_usb_tll_hs_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if *omap44xx_usb_tll_hs_slaves[] = {
+ &omap44xx_l4_cfg__usb_tll_hs,
+};
+
+static struct omap_hwmod omap44xx_usb_tll_hs_hwmod = {
+ .name = "usbhs_tll",
+ .class = &omap44xx_usb_tll_hs_hwmod_class,
+ .mpu_irqs = omap44xx_usb_tll_hs_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_usb_tll_hs_irqs),
+ .main_clk = "usb_tll_hs_ick",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_usb_tll_hs_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_usb_tll_hs_slaves),
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
/* dmm class */
@@ -5173,6 +5324,8 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_wd_timer2_hwmod,
&omap44xx_wd_timer3_hwmod,
+ &omap44xx_usb_host_hs_hwmod,
+ &omap44xx_usb_tll_hs_hwmod,
NULL,
};
--
1.6.6.1
@@ -1,160 +0,0 @@
From 70f5e1a0e6639710503a9ffb9008ddcd2bb3f06e Mon Sep 17 00:00:00 2001
From: Keshava Munegowda <Keshava_mgowda@ti.com>
Date: Wed, 1 Jun 2011 11:02:54 -0700
Subject: [PATCH 05/13] arm: omap: usb: register hwmods of usbhs
The hwmod structure of uhh and tll are retrived
and registered with omap device
Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
---
arch/arm/mach-omap2/usb-host.c | 99 ++++++++++++++--------------------------
1 files changed, 35 insertions(+), 64 deletions(-)
diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
index 89ae298..9d762c4 100644
--- a/arch/arm/mach-omap2/usb-host.c
+++ b/arch/arm/mach-omap2/usb-host.c
@@ -28,51 +28,28 @@
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <plat/usb.h>
+#include <plat/omap_device.h>
#include "mux.h"
#ifdef CONFIG_MFD_OMAP_USB_HOST
-#define OMAP_USBHS_DEVICE "usbhs-omap"
-
-static struct resource usbhs_resources[] = {
- {
- .name = "uhh",
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "tll",
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "ehci",
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "ehci-irq",
- .flags = IORESOURCE_IRQ,
- },
- {
- .name = "ohci",
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "ohci-irq",
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device usbhs_device = {
- .name = OMAP_USBHS_DEVICE,
- .id = 0,
- .num_resources = ARRAY_SIZE(usbhs_resources),
- .resource = usbhs_resources,
-};
+#define OMAP_USBHS_DEVICE "usbhs_omap"
+#define USBHS_UHH_HWMODNAME "usbhs_uhh"
+#define USBHS_TLL_HWMODNAME "usbhs_tll"
static struct usbhs_omap_platform_data usbhs_data;
static struct ehci_hcd_omap_platform_data ehci_data;
static struct ohci_hcd_omap_platform_data ohci_data;
+static struct omap_device_pm_latency omap_uhhtll_latency[] = {
+ {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
/* MUX settings for EHCI pins */
/*
* setup_ehci_io_mux - initialize IO pad mux for USBHOST
@@ -508,7 +485,10 @@ static void setup_4430ohci_io_mux(const enum usbhs_omap_port_mode *port_mode)
void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
{
- int i;
+ struct omap_hwmod *oh[2];
+ struct omap_device *od;
+ int bus_id = -1;
+ int i;
for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
usbhs_data.port_mode[i] = pdata->port_mode[i];
@@ -523,44 +503,35 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
usbhs_data.ohci_data = &ohci_data;
if (cpu_is_omap34xx()) {
- usbhs_resources[0].start = OMAP34XX_UHH_CONFIG_BASE;
- usbhs_resources[0].end = OMAP34XX_UHH_CONFIG_BASE + SZ_1K - 1;
- usbhs_resources[1].start = OMAP34XX_USBTLL_BASE;
- usbhs_resources[1].end = OMAP34XX_USBTLL_BASE + SZ_4K - 1;
- usbhs_resources[2].start = OMAP34XX_EHCI_BASE;
- usbhs_resources[2].end = OMAP34XX_EHCI_BASE + SZ_1K - 1;
- usbhs_resources[3].start = INT_34XX_EHCI_IRQ;
- usbhs_resources[4].start = OMAP34XX_OHCI_BASE;
- usbhs_resources[4].end = OMAP34XX_OHCI_BASE + SZ_1K - 1;
- usbhs_resources[5].start = INT_34XX_OHCI_IRQ;
setup_ehci_io_mux(pdata->port_mode);
setup_ohci_io_mux(pdata->port_mode);
} else if (cpu_is_omap44xx()) {
- usbhs_resources[0].start = OMAP44XX_UHH_CONFIG_BASE;
- usbhs_resources[0].end = OMAP44XX_UHH_CONFIG_BASE + SZ_1K - 1;
- usbhs_resources[1].start = OMAP44XX_USBTLL_BASE;
- usbhs_resources[1].end = OMAP44XX_USBTLL_BASE + SZ_4K - 1;
- usbhs_resources[2].start = OMAP44XX_HSUSB_EHCI_BASE;
- usbhs_resources[2].end = OMAP44XX_HSUSB_EHCI_BASE + SZ_1K - 1;
- usbhs_resources[3].start = OMAP44XX_IRQ_EHCI;
- usbhs_resources[4].start = OMAP44XX_HSUSB_OHCI_BASE;
- usbhs_resources[4].end = OMAP44XX_HSUSB_OHCI_BASE + SZ_1K - 1;
- usbhs_resources[5].start = OMAP44XX_IRQ_OHCI;
setup_4430ehci_io_mux(pdata->port_mode);
setup_4430ohci_io_mux(pdata->port_mode);
}
- if (platform_device_add_data(&usbhs_device,
- &usbhs_data, sizeof(usbhs_data)) < 0) {
- printk(KERN_ERR "USBHS platform_device_add_data failed\n");
- goto init_end;
+ oh[0] = omap_hwmod_lookup(USBHS_UHH_HWMODNAME);
+ if (!oh[0]) {
+ pr_err("Could not look up %s\n", USBHS_UHH_HWMODNAME);
+ return;
}
- if (platform_device_register(&usbhs_device) < 0)
- printk(KERN_ERR "USBHS platform_device_register failed\n");
+ oh[1] = omap_hwmod_lookup(USBHS_TLL_HWMODNAME);
+ if (!oh[1]) {
+ pr_err("Could not look up %s\n", USBHS_TLL_HWMODNAME);
+ return;
+ }
-init_end:
- return;
+ od = omap_device_build_ss(OMAP_USBHS_DEVICE, bus_id, oh, 2,
+ (void *)&usbhs_data, sizeof(usbhs_data),
+ omap_uhhtll_latency,
+ ARRAY_SIZE(omap_uhhtll_latency), false);
+
+ if (IS_ERR(od)) {
+ pr_err("Could not build hwmod devices %s, %s\n",
+ USBHS_UHH_HWMODNAME, USBHS_TLL_HWMODNAME);
+ return;
+ }
}
#else
--
1.6.6.1
@@ -1,123 +0,0 @@
From 64bc651bb56435e4cd86d2ebfa4f301abdbac6e5 Mon Sep 17 00:00:00 2001
From: Keshava Munegowda <Keshava_mgowda@ti.com>
Date: Wed, 1 Jun 2011 11:02:58 -0700
Subject: [PATCH 06/13] arm: omap: usb: device name change for the clk names of usbhs
device name usbhs clocks are changed from
usbhs-omap.0 to usbhs_omap; this is because
in the hwmod registration the device name is set
as usbhs_omap
Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
---
arch/arm/mach-omap2/clock3xxx_data.c | 28 ++++++++++++++--------------
arch/arm/mach-omap2/clock44xx_data.c | 10 +++++-----
drivers/mfd/omap-usb-host.c | 2 +-
3 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index 75b119b..fabe482 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -3285,7 +3285,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "ts_fck", &ts_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("usbhs-omap.0", "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+ CLK("usbhs_omap", "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("omap-mcbsp.1", "prcm_fck", &core_96m_fck, CK_3XXX),
CLK("omap-mcbsp.5", "prcm_fck", &core_96m_fck, CK_3XXX),
CLK(NULL, "core_96m_fck", &core_96m_fck, CK_3XXX),
@@ -3321,7 +3321,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "pka_ick", &pka_ick, CK_34XX | CK_36XX),
CLK(NULL, "core_l4_ick", &core_l4_ick, CK_3XXX),
CLK(NULL, "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("usbhs-omap.0", "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+ CLK("usbhs_omap", "usbtll_ick", &usbtll_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("omap_hsmmc.2", "ick", &mmchs3_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "icr_ick", &icr_ick, CK_34XX | CK_36XX),
CLK("omap-aes", "ick", &aes2_ick, CK_34XX | CK_36XX),
@@ -3367,20 +3367,20 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cam_ick", &cam_ick, CK_34XX | CK_36XX),
CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_34XX | CK_36XX),
CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("usbhs-omap.0", "hs_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+ CLK("usbhs_omap", "hs_fck", &usbhost_120m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("usbhs-omap.0", "fs_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+ CLK("usbhs_omap", "fs_fck", &usbhost_48m_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("usbhs-omap.0", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("usbhs-omap.0", "utmi_p1_gfclk", &dummy_ck, CK_3XXX),
- CLK("usbhs-omap.0", "utmi_p2_gfclk", &dummy_ck, CK_3XXX),
- CLK("usbhs-omap.0", "xclk60mhsp1_ck", &dummy_ck, CK_3XXX),
- CLK("usbhs-omap.0", "xclk60mhsp2_ck", &dummy_ck, CK_3XXX),
- CLK("usbhs-omap.0", "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX),
- CLK("usbhs-omap.0", "usb_host_hs_utmi_p2_clk", &dummy_ck, CK_3XXX),
- CLK("usbhs-omap.0", "usb_tll_hs_usb_ch0_clk", &dummy_ck, CK_3XXX),
- CLK("usbhs-omap.0", "usb_tll_hs_usb_ch1_clk", &dummy_ck, CK_3XXX),
- CLK("usbhs-omap.0", "init_60m_fclk", &dummy_ck, CK_3XXX),
+ CLK("usbhs_omap", "usbhost_ick", &usbhost_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+ CLK("usbhs_omap", "utmi_p1_gfclk", &dummy_ck, CK_3XXX),
+ CLK("usbhs_omap", "utmi_p2_gfclk", &dummy_ck, CK_3XXX),
+ CLK("usbhs_omap", "xclk60mhsp1_ck", &dummy_ck, CK_3XXX),
+ CLK("usbhs_omap", "xclk60mhsp2_ck", &dummy_ck, CK_3XXX),
+ CLK("usbhs_omap", "usb_host_hs_utmi_p1_clk", &dummy_ck, CK_3XXX),
+ CLK("usbhs_omap", "usb_host_hs_utmi_p2_clk", &dummy_ck, CK_3XXX),
+ CLK("usbhs_omap", "usb_tll_hs_usb_ch0_clk", &dummy_ck, CK_3XXX),
+ CLK("usbhs_omap", "usb_tll_hs_usb_ch1_clk", &dummy_ck, CK_3XXX),
+ CLK("usbhs_omap", "init_60m_fclk", &dummy_ck, CK_3XXX),
CLK(NULL, "usim_fck", &usim_fck, CK_3430ES2PLUS | CK_36XX),
CLK(NULL, "gpt1_fck", &gpt1_fck, CK_3XXX),
CLK(NULL, "wkup_32k_fck", &wkup_32k_fck, CK_3XXX),
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index 8c96567..34e91eb 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3205,7 +3205,7 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "uart3_fck", &uart3_fck, CK_443X),
CLK(NULL, "uart4_fck", &uart4_fck, CK_443X),
CLK(NULL, "usb_host_fs_fck", &usb_host_fs_fck, CK_443X),
- CLK("usbhs-omap.0", "fs_fck", &usb_host_fs_fck, CK_443X),
+ CLK("usbhs_omap", "fs_fck", &usb_host_fs_fck, CK_443X),
CLK(NULL, "utmi_p1_gfclk", &utmi_p1_gfclk, CK_443X),
CLK(NULL, "usb_host_hs_utmi_p1_clk", &usb_host_hs_utmi_p1_clk, CK_443X),
CLK(NULL, "utmi_p2_gfclk", &utmi_p2_gfclk, CK_443X),
@@ -3217,8 +3217,8 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "usb_host_hs_hsic480m_p2_clk", &usb_host_hs_hsic480m_p2_clk, CK_443X),
CLK(NULL, "usb_host_hs_func48mclk", &usb_host_hs_func48mclk, CK_443X),
CLK(NULL, "usb_host_hs_fck", &usb_host_hs_fck, CK_443X),
- CLK("usbhs-omap.0", "hs_fck", &usb_host_hs_fck, CK_443X),
- CLK("usbhs-omap.0", "usbhost_ick", &dummy_ck, CK_443X),
+ CLK("usbhs_omap", "hs_fck", &usb_host_hs_fck, CK_443X),
+ CLK("usbhs_omap", "usbhost_ick", &dummy_ck, CK_443X),
CLK(NULL, "otg_60m_gfclk", &otg_60m_gfclk, CK_443X),
CLK(NULL, "usb_otg_hs_xclk", &usb_otg_hs_xclk, CK_443X),
CLK("musb-omap2430", "ick", &usb_otg_hs_ick, CK_443X),
@@ -3227,8 +3227,8 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "usb_tll_hs_usb_ch0_clk", &usb_tll_hs_usb_ch0_clk, CK_443X),
CLK(NULL, "usb_tll_hs_usb_ch1_clk", &usb_tll_hs_usb_ch1_clk, CK_443X),
CLK(NULL, "usb_tll_hs_ick", &usb_tll_hs_ick, CK_443X),
- CLK("usbhs-omap.0", "usbtll_ick", &usb_tll_hs_ick, CK_443X),
- CLK("usbhs-omap.0", "usbtll_fck", &dummy_ck, CK_443X),
+ CLK("usbhs_omap", "usbtll_ick", &usb_tll_hs_ick, CK_443X),
+ CLK("usbhs_omap", "usbtll_fck", &dummy_ck, CK_443X),
CLK(NULL, "usim_ck", &usim_ck, CK_443X),
CLK(NULL, "usim_fclk", &usim_fclk, CK_443X),
CLK(NULL, "usim_fck", &usim_fck, CK_443X),
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 8552195..43de12a 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -28,7 +28,7 @@
#include <plat/usb.h>
#include <linux/pm_runtime.h>
-#define USBHS_DRIVER_NAME "usbhs-omap"
+#define USBHS_DRIVER_NAME "usbhs_omap"
#define OMAP_EHCI_DEVICE "ehci-omap"
#define OMAP_OHCI_DEVICE "ohci-omap3"
--
1.6.6.1
@@ -1,165 +0,0 @@
From bf583f2924fd9b2f0356cbd0bbfd58c48d98ef15 Mon Sep 17 00:00:00 2001
From: Keshava Munegowda <Keshava_mgowda@ti.com>
Date: Wed, 1 Jun 2011 11:03:03 -0700
Subject: [PATCH 07/13] mfd: global Suspend and resume support of ehci and ohci
The global suspend and resume functions for usbhs core driver
are implemented.These routine are called when the global suspend
and resume occurs. Before calling these functions, the
bus suspend and resume of ehci and ohci drivers are called
from runtime pm.
Signed-off-by: Keshava Munegowda <keshava_mgowda@ti.com>
---
drivers/mfd/omap-usb-host.c | 103 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 103 insertions(+), 0 deletions(-)
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 43de12a..32d19e2 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -146,6 +146,10 @@
#define is_ehci_hsic_mode(x) (x == OMAP_EHCI_PORT_MODE_HSIC)
+/* USBHS state bits */
+#define OMAP_USBHS_INIT 0
+#define OMAP_USBHS_SUSPEND 4
+
struct usbhs_hcd_omap {
struct clk *xclk60mhsp1_ck;
struct clk *xclk60mhsp2_ck;
@@ -165,6 +169,7 @@ struct usbhs_hcd_omap {
u32 usbhs_rev;
spinlock_t lock;
int count;
+ unsigned long state;
};
/*-------------------------------------------------------------------------*/
@@ -809,6 +814,8 @@ static int usbhs_enable(struct device *dev)
(pdata->ehci_data->reset_gpio_port[1], 1);
}
+ set_bit(OMAP_USBHS_INIT, &omap->state);
+
end_count:
omap->count++;
spin_unlock_irqrestore(&omap->lock, flags);
@@ -897,6 +904,7 @@ static void usbhs_disable(struct device *dev)
}
pm_runtime_put_sync(dev);
+ clear_bit(OMAP_USBHS_INIT, &omap->state);
/* The gpio_free migh sleep; so unlock the spinlock */
spin_unlock_irqrestore(&omap->lock, flags);
@@ -926,10 +934,105 @@ void omap_usbhs_disable(struct device *dev)
}
EXPORT_SYMBOL_GPL(omap_usbhs_disable);
+#ifdef CONFIG_PM
+
+static int usbhs_resume(struct device *dev)
+{
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
+ unsigned long flags = 0;
+
+ dev_dbg(dev, "Resuming TI HSUSB Controller\n");
+
+ if (!pdata) {
+ dev_dbg(dev, "missing platform_data\n");
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&omap->lock, flags);
+
+ if (!test_bit(OMAP_USBHS_INIT, &omap->state) ||
+ !test_bit(OMAP_USBHS_SUSPEND, &omap->state))
+ goto end_resume;
+
+ pm_runtime_get_sync(dev);
+
+ if (is_omap_usbhs_rev2(omap)) {
+ if (is_ehci_tll_mode(pdata->port_mode[0])) {
+ clk_enable(omap->usbhost_p1_fck);
+ clk_enable(omap->usbtll_p1_fck);
+ }
+ if (is_ehci_tll_mode(pdata->port_mode[1])) {
+ clk_enable(omap->usbhost_p2_fck);
+ clk_enable(omap->usbtll_p2_fck);
+ }
+ clk_enable(omap->utmi_p1_fck);
+ clk_enable(omap->utmi_p2_fck);
+ }
+ clear_bit(OMAP_USBHS_SUSPEND, &omap->state);
+
+end_resume:
+ spin_unlock_irqrestore(&omap->lock, flags);
+ return 0;
+}
+
+
+static int usbhs_suspend(struct device *dev)
+{
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
+ unsigned long flags = 0;
+
+ dev_dbg(dev, "Suspending TI HSUSB Controller\n");
+
+ if (!pdata) {
+ dev_dbg(dev, "missing platform_data\n");
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&omap->lock, flags);
+
+ if (!test_bit(OMAP_USBHS_INIT, &omap->state) ||
+ test_bit(OMAP_USBHS_SUSPEND, &omap->state))
+ goto end_suspend;
+
+ if (is_omap_usbhs_rev2(omap)) {
+ if (is_ehci_tll_mode(pdata->port_mode[0])) {
+ clk_disable(omap->usbhost_p1_fck);
+ clk_disable(omap->usbtll_p1_fck);
+ }
+ if (is_ehci_tll_mode(pdata->port_mode[1])) {
+ clk_disable(omap->usbhost_p2_fck);
+ clk_disable(omap->usbtll_p2_fck);
+ }
+ clk_disable(omap->utmi_p2_fck);
+ clk_disable(omap->utmi_p1_fck);
+ }
+
+ set_bit(OMAP_USBHS_SUSPEND, &omap->state);
+ pm_runtime_put_sync(dev);
+
+end_suspend:
+ spin_unlock_irqrestore(&omap->lock, flags);
+ return 0;
+}
+
+
+static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
+ .suspend = usbhs_suspend,
+ .resume = usbhs_resume,
+};
+
+#define USBHS_OMAP_DEV_PM_OPS (&usbhsomap_dev_pm_ops)
+#else
+#define USBHS_OMAP_DEV_PM_OPS NULL
+#endif
+
static struct platform_driver usbhs_omap_driver = {
.driver = {
.name = (char *)usbhs_driver_name,
.owner = THIS_MODULE,
+ .pm = USBHS_OMAP_DEV_PM_OPS,
},
.remove = __exit_p(usbhs_omap_remove),
};
--
1.6.6.1
@@ -1,36 +0,0 @@
From 1f2e639755b920398d6592775e0e31f7fb1ca955 Mon Sep 17 00:00:00 2001
From: Lesly A M <leslyam@ti.com>
Date: Wed, 1 Jun 2011 14:56:38 -0700
Subject: [PATCH 08/13] MFD: TWL4030: Correct the warning print during script loading
Correcting the if condition check for printing the warning,
if wakeup script is not updated before updating the sleep script.
Since the flag 'order' is set to '1' while updating the wakeup script for P1P2,
the condition checking for printing the warning should be if(!order)
(ie: print the warning if wakeup script is not updated before updating the sleep script)
Signed-off-by: Lesly A M <leslyam@ti.com>
Cc: Nishanth Menon <nm@ti.com>
Cc: David Derrick <dderrick@ti.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/twl4030-power.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 2c0d4d1..8373d79 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -448,7 +448,7 @@ static int __init load_twl4030_script(struct twl4030_script *tscript,
goto out;
}
if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
- if (order)
+ if (!order)
pr_warning("TWL4030: Bad order of scripts (sleep "\
"script before wakeup) Leads to boot"\
"failure on some boards\n");
--
1.6.6.1
@@ -1,61 +0,0 @@
From ea9acebfe2d3ca8fb3969eaf327665632142b85d Mon Sep 17 00:00:00 2001
From: Lesly A M <leslyam@ti.com>
Date: Wed, 1 Jun 2011 14:56:45 -0700
Subject: [PATCH 09/13] MFD: TWL4030: Modifying the macro name Main_Ref to all caps
Modifying the macro name Main_Ref to all caps(MAIN_REF).
Suggested by Nishanth Menon <nm@ti.com>
Signed-off-by: Lesly A M <leslyam@ti.com>
Cc: Nishanth Menon <nm@ti.com>
Cc: David Derrick <dderrick@ti.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
arch/arm/mach-omap2/board-rx51-peripherals.c | 2 +-
drivers/mfd/twl4030-power.c | 2 +-
include/linux/i2c/twl.h | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index bbcb677..01ee0a1 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -730,7 +730,7 @@ static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
{ .resource = RES_RESET, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
- { .resource = RES_Main_Ref, .devgroup = -1,
+ { .resource = RES_MAIN_REF, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ 0, 0},
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 8373d79..8162e43 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -120,7 +120,7 @@ static u8 res_config_addrs[] = {
[RES_HFCLKOUT] = 0x8b,
[RES_32KCLKOUT] = 0x8e,
[RES_RESET] = 0x91,
- [RES_Main_Ref] = 0x94,
+ [RES_MAIN_REF] = 0x94,
};
static int __init twl4030_write_script_byte(u8 address, u8 byte)
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index cbbf3b3..aee3a22 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -502,7 +502,7 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
#define RES_32KCLKOUT 26
#define RES_RESET 27
/* Power Reference */
-#define RES_Main_Ref 28
+#define RES_MAIN_REF 28
#define TOTAL_RESOURCES 28
/*
--
1.6.6.1
@@ -1,705 +0,0 @@
From 0b29e1f61b85dd2d04f035088b70dc287d15b9f0 Mon Sep 17 00:00:00 2001
From: Lesly A M <leslyam@ti.com>
Date: Wed, 1 Jun 2011 14:56:49 -0700
Subject: [PATCH 10/13] MFD: TWL4030: power scripts for OMAP3 boards
Power bus message sequence for TWL4030 to enter sleep/wakeup/warm_reset.
TWL4030 power scripts which can be used by different OMAP3 boards
with the power companion chip (TWL4030 series).
The twl4030 generic script can be used by any board file to update
the power data in twl4030_platform_data.
Since the TWL4030 power script has dependency with APIs in twl4030-power.c
removing the __init for these APIs.
For more information please see:
http://omapedia.org/wiki/TWL4030_power_scripts
Signed-off-by: Lesly A M <leslyam@ti.com>
Cc: Nishanth Menon <nm@ti.com>
Cc: David Derrick <dderrick@ti.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
arch/arm/configs/omap2plus_defconfig | 1 +
arch/arm/mach-omap2/devices.c | 15 ++
drivers/mfd/Kconfig | 11 +
drivers/mfd/Makefile | 1 +
drivers/mfd/twl4030-power.c | 31 ++--
drivers/mfd/twl4030-script-omap.c | 373 ++++++++++++++++++++++++++++++++++
include/linux/i2c/twl.h | 41 ++++-
7 files changed, 454 insertions(+), 19 deletions(-)
create mode 100644 drivers/mfd/twl4030-script-omap.c
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 076db52..d9b9858 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -184,6 +184,7 @@ CONFIG_TWL4030_WATCHDOG=y
CONFIG_MENELAUS=y
CONFIG_TWL4030_CORE=y
CONFIG_TWL4030_POWER=y
+CONFIG_TWL4030_SCRIPT=m
CONFIG_REGULATOR=y
CONFIG_REGULATOR_TWL4030=y
CONFIG_REGULATOR_TPS65023=y
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 7b85585..7653329 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -329,6 +329,20 @@ static void omap_init_audio(void)
static inline void omap_init_audio(void) {}
#endif
+#ifdef CONFIG_ARCH_OMAP3
+static struct platform_device omap_twl4030_script = {
+ .name = "twl4030_script",
+ .id = -1,
+};
+
+static void omap_init_twl4030_script(void)
+{
+ platform_device_register(&omap_twl4030_script);
+}
+#else
+static inline void omap_init_twl4030_script(void) {}
+#endif
+
#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
#include <plat/mcspi.h>
@@ -691,6 +705,7 @@ static int __init omap2_init_devices(void)
omap_init_sham();
omap_init_aes();
omap_init_vout();
+ omap_init_twl4030_script();
return 0;
}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index fe2370a..ea25d93 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -204,6 +204,17 @@ config TWL4030_POWER
and load scripts controlling which resources are switched off/on
or reset when a sleep, wakeup or warm reset event occurs.
+config TWL4030_SCRIPT
+ tristate "Support TWL4030 script for OMAP3 boards"
+ depends on TWL4030_CORE && TWL4030_POWER
+ help
+ Say yes here if you want to use the twl4030 power scripts
+ for OMAP3 boards. Power bus message sequence for
+ TWL4030 to enter sleep/wakeup/warm_reset.
+
+ TWL4030 power scripts which can be used by different
+ OMAP3 boards with the power companion chip (TWL4030 series).
+
config TWL4030_CODEC
bool
depends on TWL4030_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 419caa9..53ada21 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
+obj-$(CONFIG_TWL4030_SCRIPT) += twl4030-script-omap.o
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 8162e43..91d5bc8 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -123,7 +123,7 @@ static u8 res_config_addrs[] = {
[RES_MAIN_REF] = 0x94,
};
-static int __init twl4030_write_script_byte(u8 address, u8 byte)
+static int twl4030_write_script_byte(u8 address, u8 byte)
{
int err;
@@ -137,7 +137,7 @@ out:
return err;
}
-static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
+static int twl4030_write_script_ins(u8 address, u16 pmb_message,
u8 delay, u8 next)
{
int err;
@@ -157,7 +157,7 @@ out:
return err;
}
-static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
+static int twl4030_write_script(u8 address, struct twl4030_ins *script,
int len)
{
int err;
@@ -182,7 +182,7 @@ static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
return err;
}
-static int __init twl4030_config_wakeup3_sequence(u8 address)
+static int twl4030_config_wakeup3_sequence(u8 address)
{
int err;
u8 data;
@@ -207,7 +207,7 @@ out:
return err;
}
-static int __init twl4030_config_wakeup12_sequence(u8 address)
+static int twl4030_config_wakeup12_sequence(u8 address)
{
int err = 0;
u8 data;
@@ -261,7 +261,7 @@ out:
return err;
}
-static int __init twl4030_config_sleep_sequence(u8 address)
+static int twl4030_config_sleep_sequence(u8 address)
{
int err;
@@ -275,7 +275,7 @@ static int __init twl4030_config_sleep_sequence(u8 address)
return err;
}
-static int __init twl4030_config_warmreset_sequence(u8 address)
+static int twl4030_config_warmreset_sequence(u8 address)
{
int err;
u8 rd_data;
@@ -323,7 +323,7 @@ out:
return err;
}
-static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
+static int twl4030_configure_resource(struct twl4030_resconfig *rconfig)
{
int rconfig_addr;
int err;
@@ -415,7 +415,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
return 0;
}
-static int __init load_twl4030_script(struct twl4030_script *tscript,
+static int load_twl4030_script(struct twl4030_script *tscript,
u8 address)
{
int err;
@@ -510,8 +510,9 @@ int twl4030_remove_script(u8 flags)
return err;
}
+EXPORT_SYMBOL_GPL(twl4030_remove_script);
-void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
+int twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
{
int err = 0;
int i;
@@ -529,7 +530,6 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)
goto unlock;
-
for (i = 0; i < twl4030_scripts->num; i++) {
err = load_twl4030_script(twl4030_scripts->scripts[i], address);
if (err)
@@ -552,18 +552,19 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)
pr_err("TWL4030 Unable to relock registers\n");
- return;
+ return err;
unlock:
if (err)
pr_err("TWL4030 Unable to unlock registers\n");
- return;
+ return err;
load:
if (err)
pr_err("TWL4030 failed to load scripts\n");
- return;
+ return err;
resource:
if (err)
pr_err("TWL4030 failed to configure resource\n");
- return;
+ return err;
}
+EXPORT_SYMBOL_GPL(twl4030_power_init);
diff --git a/drivers/mfd/twl4030-script-omap.c b/drivers/mfd/twl4030-script-omap.c
new file mode 100644
index 0000000..867a442
--- /dev/null
+++ b/drivers/mfd/twl4030-script-omap.c
@@ -0,0 +1,373 @@
+/*
+ * OMAP power script for PMIC TWL4030
+ *
+ * Author: Lesly A M <leslyam@ti.com>
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Lesly A M <leslyam@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/i2c/twl.h>
+
+/*
+ * power management signal connections for OMAP3430 with TWL5030
+ *
+ * TWL5030 OMAP3430
+ * ______________________ _____________________
+ * | | | |
+ * | (P1) NSLEEP1|<----------|SYS_OFFMODE |
+ * | NRESWARM|<----------|NWARMRESET |
+ * | (P2) NSLEEP2|---| | |
+ * | | === | |
+ * | | - | |
+ * | | | |
+ * | VDD1 |---------->| VDD1 |
+ * | VDD2 |---------->| VDD2 |
+ * | VIO |---------->| VDDS |
+ * ________ | VAUX1 | | |
+ * | | | ... | | |
+ * | ENABLE|<--------|CLKEN CLKREQ|<----------|SYS_CLKREQ |
+ * | CLKOUT|-------->|HFCLKIN (P3) HFCLKOUT|---------->|XTALIN |
+ * |________| |______________________| |_____________________|
+ *
+ *
+ * Signal descriptions:
+ *
+ * SYS_OFFMODE - OMAP drives this signal low only when the OMAP is in the
+ * OFF idle mode. It is driven high when a wake up event is detected.
+ * This signal should control the P1 device group in the PMIC.
+ *
+ * SYS_CLKREQ - OMAP should drive this signal low when the OMAP goes into
+ * any idle mode. This signal should control the P3 device group
+ * in the PMIC. It is used to notify PMIC when XTALIN is no longer needed.
+ *
+ * NSLEEP1(P1) - When this signal goes low the P1 sleep sequence is executed
+ * in the PMIC turning off certain resources. When this signal goes high
+ * the P1 active sequence is executed turning back on certain resources.
+ *
+ * NSLEEP2(P2) - This signal controls the P2 device group of the PMIC.
+ * It is not used in this setup and should be tied to ground.
+ * This can be used for connecting a different processor or MODEM chip.
+ *
+ * CLKREQ(P3) - When this signal goes low the P3 sleep sequence is executed
+ * in the PMIC turning off HFCLKOUT. When this signal goes high
+ * the P3 active sequence is executed turning back on HFCLKOUT and other
+ * resources.
+ *
+ * CLKEN - Enable signal for oscillator. Should only go low when OMAP is
+ * in the OFF idle mode due to long oscillator startup times.
+ *
+ * HFCLKIN - Oscillator output clock into PMIC.
+ *
+ * HFCLKOUT - System clock output from PMIC to OMAP.
+ *
+ * XTALIN - OMAP system clock input(HFCLKOUT).
+ */
+
+/*
+ * Recommended sleep and active sequences for TWL5030 when connected to OMAP3
+ *
+ * WARNING: If the board is using NSLEEP2(P2), should modify this script and
+ * setuptime values accordingly.
+ *
+ * Chip Retention/Off (using i2c for scaling voltage):
+ * When OMAP de-assert the SYS_CLKREQ signal, only HFCLKOUT is affected
+ * since it is the only resource assigned to P3 only.
+ *
+ * Sysoff (using sys_off signal):
+ * When OMAP de-assert the SYS_OFFMODE signal A2S(active to sleep sequence)
+ * on the PMIC is executed. This will put resources of TYPE2=1 and TYPE2=2
+ * into sleep. At this point only resources assigned to P1 only will be
+ * affected (VDD1, VDD2 & VPLL1).
+ *
+ * Next the OMAP will lower SYS_CLKREQ which will allow the A2S sequence
+ * in PMIC to execute again. This will put resources of TYPE2=1 and TYPE2=2
+ * into sleep but will affect resources that are assigned to P3(HFCLKOUT)
+ * only or assigned to P1 and P3.
+ *
+ * On wakeup event OMAP goes active and pulls the SYS_CLKREQ high,
+ * which will execute the P3 S2A sequence on the PMIC. This will turn on
+ * resources assigned to P3 or assigned to P1 and P3 and of TYPE2=2.
+ *
+ * Next the OMAP will wait the PRM_VOLTOFFSET time and then de-assert
+ * the SYS_OFFMODE pin allowing the PMIC to execute the P1 S2A active
+ * sequence. This will turn on resources assigned to P1 or assigned to
+ * P1 and P3 and of TYPE2=1.
+ *
+ * Timing diagram for OMAP wakeup from OFFMODE using sys_off signal
+ * _____________________________________________________________
+ * OMAP active __/
+ * |<--------------------PRM_CLKSETP-------------------->|
+ * ______________________________________________________
+ * SYS_CLKREQ _________/
+ * ___________________________________________________
+ * CLKEN ____________/
+ *
+ * HFCLKIN _______________________________________________/////////////////
+ *
+ * HFCLKOUT __________________________________________________//////////////
+ * |<---PRM_VOLTOFFSET-->|
+ * ________________________________
+ * SYS_OFFMODE _______________________________/
+ * |<--------PRM_VOLTSETUP2------->|
+ * ___________
+ * VPLL1 ____________________________________________________/
+ * __
+ * VDD1 _____________________________________________________________/
+ * __
+ * VDD2 _____________________________________________________________/
+ *
+ * Other resources which are not handled by this script should be
+ * controlled by the respective drivers using them (VAUX1, VAUX2, VAUX3,
+ * VAUX4, VMMC1, VMMC2, VPLL2, VSIM, VDAC, VUSB1V5, VUSB1V8 & VUSB3V1).
+ *
+ * More info:
+ * http://omapedia.org/wiki/TWL4030_power_scripts
+ */
+
+/**
+ * DOC: Sleep to active sequence for P1/P2
+ *
+ * Sequence to control the TWL4030 Power resources,
+ * when the system wakeup from sleep.
+ * Executed upon P1_P2 transition for wakeup
+ * (sys_offmode signal de-asserted on OMAP).
+ */
+static struct twl4030_ins wakeup_p12_seq[] __initdata = {
+ /*
+ * Broadcast message to put resources to active
+ *
+ * Since we are not using TYPE, resources which have TYPE2 configured
+ * as 1 will be targeted (VPLL1, VDD1, VDD2, REGEN, NRES_PWRON, SYSEN).
+ */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1,
+ RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p12_script __initdata = {
+ .script = wakeup_p12_seq,
+ .size = ARRAY_SIZE(wakeup_p12_seq),
+ .flags = TWL4030_WAKEUP12_SCRIPT,
+};
+
+/**
+ * DOC: Sleep to active sequence for P3
+ *
+ * Sequence to control the TWL4030 Power resources,
+ * when the system wakeup from sleep.
+ * Executed upon P3 transition for wakeup
+ * (clkreq signal asserted on OMAP).
+ */
+static struct twl4030_ins wakeup_p3_seq[] __initdata = {
+ /*
+ * Broadcast message to put resources to active
+ *
+ * Since we are not using TYPE, resources which have TYPE2 configured
+ * as 2 will be targeted
+ * (VINTANA1, VINTANA2, VINTDIG, VIO, CLKEN, HFCLKOUT).
+ */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2,
+ RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p3_script __initdata = {
+ .script = wakeup_p3_seq,
+ .size = ARRAY_SIZE(wakeup_p3_seq),
+ .flags = TWL4030_WAKEUP3_SCRIPT,
+};
+
+/**
+ * DOC: Active to sleep sequence for P1/P2/P3
+ *
+ * Sequence to control the TWL4030 Power resources,
+ * when the system goes into sleep.
+ * Executed upon P1_P2/P3 transition for sleep.
+ * (sys_offmode signal asserted/clkreq de-asserted on OMAP).
+ */
+static struct twl4030_ins sleep_on_seq[] __initdata = {
+ /* Broadcast message to put res to sleep (TYPE2 = 1, 2) */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1,
+ RES_STATE_SLEEP), 2},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2,
+ RES_STATE_SLEEP), 2},
+};
+
+static struct twl4030_script sleep_on_script __initdata = {
+ .script = sleep_on_seq,
+ .size = ARRAY_SIZE(sleep_on_seq),
+ .flags = TWL4030_SLEEP_SCRIPT,
+};
+
+/**
+ * DOC: Warm reset sequence
+ *
+ * Sequence to reset the TWL4030 Power resources,
+ * when the system gets warm reset.
+ * Executed upon warm reset signal.
+ *
+ * First the device is put in reset, then the system clock is requested to
+ * the external oscillator, and default ON power reference and power providers
+ * are enabled. Next some additional resources which are software controlled
+ * are enabled. Finally sequence is ended by the release of TWL5030 reset.
+ */
+static struct twl4030_ins wrst_seq[] __initdata = {
+ /*
+ * As a workaround for OMAP Erratum (ID: i537 - OMAP HS devices are
+ * not recovering from warm reset while in OFF mode)
+ * NRESPWRON is toggled to force a power on reset condition to OMAP
+ */
+ /* Trun OFF NRES_PWRON */
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_NRES_PWRON, RES_STATE_OFF), 2},
+ /* Reset twl4030 */
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_OFF), 2},
+ /* Reset MAIN_REF */
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_MAIN_REF, RES_STATE_WRST), 2},
+ /* Reset All type2_group2 */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2,
+ RES_STATE_WRST), 2},
+ /* Reset VUSB_3v1 */
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_VUSB_3V1, RES_STATE_WRST), 2},
+ /* Reset All type2_group1 */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1,
+ RES_STATE_WRST), 2},
+ /* Reset the Reset & Contorl_signals */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0,
+ RES_STATE_WRST), 2},
+ /* Re-enable twl4030 */
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_ACTIVE), 2},
+ /* Trun ON NRES_PWRON */
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_NRES_PWRON, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wrst_script __initdata = {
+ .script = wrst_seq,
+ .size = ARRAY_SIZE(wrst_seq),
+ .flags = TWL4030_WRST_SCRIPT,
+};
+
+/* TWL4030 script for sleep, wakeup & warm_reset */
+static struct twl4030_script *twl4030_scripts[] __initdata = {
+ &wakeup_p12_script,
+ &wakeup_p3_script,
+ &sleep_on_script,
+ &wrst_script,
+};
+
+/**
+ * DOC: TWL4030 resource configuration
+ *
+ * Resource which are attached to P1 device group alone
+ * will go to sleep state, when sys_off signal from OMAP is de-asserted.
+ * (VPLL1, VDD1, VDD2)
+ *
+ * None of the resources are attached to P2 device group alone.
+ * (WARNING: If MODEM or connectivity chip is connected to NSLEEP2 PIN on
+ * TWL4030, should modify the resource configuration accordingly).
+ *
+ * Resource which are attached to P3 device group alone
+ * will go to sleep state, when clk_req signal from OMAP is de-asserted.
+ * (HFCLKOUT)
+ *
+ * Resource which are attached to more than one device group
+ * will go to sleep state, when corresponding signals are de-asserted.
+ * (VINTANA1, VINTANA2, VINTDIG, VIO, REGEN, NRESPWRON, CLKEN, SYSEN)
+ *
+ * REGEN is an output of the device which can be connected to slave power ICs
+ * or external LDOs that power on before voltage for the IO interface (VIO).
+ *
+ * SYSEN is a bidirectional signal of the device that controls slave power ICs.
+ * In master mode, the device sets SYSEN high to enable the slave power ICs.
+ * In slave mode, when one of the power ICs drives the SYSEN signal low,
+ * all devices of the platform stay in the wait-on state.
+ *
+ * Resource which are attached to none of the device group by default
+ * will be in sleep state. These resource should be controlled by
+ * the respective drivers using them.
+ * Resource which are controlled by drivers are not modified here.
+ * (VAUX1, VAUX2, VAUX3, VAUX4, VMMC1, VMMC2, VPLL2, VSIM, VDAC,
+ * VUSB1V5, VUSB1V8, VUSB3V1)
+ *
+ * Resource using reset values.
+ * (32KCLKOUT, TRITON_RESET, MAINREF)
+ */
+static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
+ { .resource = RES_VPLL1, .devgroup = DEV_GRP_P1, .type = 3,
+ .type2 = 1, .remap_sleep = RES_STATE_OFF },
+ { .resource = RES_VINTANA1, .devgroup = DEV_GRP_ALL, .type = 1,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_VINTANA2, .devgroup = DEV_GRP_ALL, .type = 0,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_VINTDIG, .devgroup = DEV_GRP_ALL, .type = 1,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_VIO, .devgroup = DEV_GRP_ALL, .type = 2,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_VDD1, .devgroup = DEV_GRP_P1,
+ .type = 4, .type2 = 1, .remap_sleep = RES_STATE_OFF },
+ { .resource = RES_VDD2, .devgroup = DEV_GRP_P1,
+ .type = 3, .type2 = 1, .remap_sleep = RES_STATE_OFF },
+ { .resource = RES_REGEN, .devgroup = DEV_GRP_ALL, .type = 2,
+ .type2 = 1, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_NRES_PWRON, .devgroup = DEV_GRP_ALL, .type = 0,
+ .type2 = 1, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_CLKEN, .devgroup = DEV_GRP_ALL, .type = 3,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_SYSEN, .devgroup = DEV_GRP_ALL, .type = 6,
+ .type2 = 1, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3,
+ .type = 0, .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { 0, 0},
+};
+
+struct twl4030_power_data twl4030_generic_script __initdata = {
+ .scripts = twl4030_scripts,
+ .num = ARRAY_SIZE(twl4030_scripts),
+ .resource_config = twl4030_rconfig,
+};
+
+static int __init twl4030_script_probe(struct platform_device *pdev)
+{
+ return twl4030_power_init(&twl4030_generic_script);
+}
+
+static int twl4030_script_remove(struct platform_device *pdev)
+{
+ return twl4030_remove_script(TWL4030_SLEEP_SCRIPT |
+ TWL4030_WAKEUP12_SCRIPT | TWL4030_WAKEUP3_SCRIPT |
+ TWL4030_WRST_SCRIPT);
+}
+
+static struct platform_driver twl4030_script_driver = {
+ .remove = twl4030_script_remove,
+ .driver = {
+ .name = "twl4030_script",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init twl4030_script_init(void)
+{
+ /* Register the TWL4030 script driver */
+ return platform_driver_probe(&twl4030_script_driver,
+ twl4030_script_probe);
+}
+
+static void __exit twl4030_script_cleanup(void)
+{
+ /* Unregister TWL4030 script driver */
+ platform_driver_unregister(&twl4030_script_driver);
+}
+
+module_init(twl4030_script_init);
+module_exit(twl4030_script_cleanup);
+
+MODULE_DESCRIPTION("OMAP TWL4030 script driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index aee3a22..f343974 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -205,6 +205,12 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
return -EIO;
}
#endif
+
+#ifdef CONFIG_TWL4030_POWER
+extern struct twl4030_power_data twl4030_generic_script;
+#else
+#define twl4030_generic_script NULL;
+#endif
/*----------------------------------------------------------------------*/
/*
@@ -437,9 +443,23 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
/* Power bus message definitions */
-/* The TWL4030/5030 splits its power-management resources (the various
- * regulators, clock and reset lines) into 3 processor groups - P1, P2 and
- * P3. These groups can then be configured to transition between sleep, wait-on
+/*
+ * The TWL4030/5030 splits its power-management resources (the various
+ * regulators, clock and reset lines) into 3 processor groups - P1, P2 and P3.
+ *
+ * Resources attached to device group P1 is managed depending on the state of
+ * NSLEEP1 pin of TWL4030, which is connected to sys_off signal from OMAP
+ *
+ * Resources attached to device group P2 is managed depending on the state of
+ * NSLEEP2 pin of TWL4030, which is can be connected to a modem or
+ * connectivity chip
+ *
+ * Resources attached to device group P3 is managed depending on the state of
+ * CLKREQ pin of TWL4030, which is connected to clk request signal from OMAP
+ *
+ * If required these resources can be attached to combination of P1/P2/P3.
+ *
+ * These groups can then be configured to transition between sleep, wait-on
* and active states by sending messages to the power bus. See Section 5.4.2
* Power Resources of TWL4030 TRM
*/
@@ -449,7 +469,17 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
#define DEV_GRP_P1 0x1 /* P1: all OMAP devices */
#define DEV_GRP_P2 0x2 /* P2: all Modem devices */
#define DEV_GRP_P3 0x4 /* P3: all peripheral devices */
+#define DEV_GRP_ALL 0x7 /* P1/P2/P3: all devices */
+/*
+ * The 27 power resources in TWL4030 is again divided into
+ * analog resources:
+ * Power Providers - LDO regulators, dc-to-dc regulators
+ * Power Reference - analog reference
+ *
+ * and digital resources:
+ * Reset & Clock - reset and clock signals.
+ */
/* Resource groups */
#define RES_GRP_RES 0x0 /* Reserved */
#define RES_GRP_PP 0x1 /* Power providers */
@@ -461,7 +491,10 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
#define RES_GRP_ALL 0x7 /* All resource groups */
#define RES_TYPE2_R0 0x0
+#define RES_TYPE2_R1 0x1
+#define RES_TYPE2_R2 0x2
+#define RES_TYPE_R0 0x0
#define RES_TYPE_ALL 0x7
/* Resource states */
@@ -636,7 +669,7 @@ struct twl4030_power_data {
#define TWL4030_RESCONFIG_UNDEF ((u8)-1)
};
-extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
+extern int twl4030_power_init(struct twl4030_power_data *triton2_scripts);
extern int twl4030_remove_script(u8 flags);
struct twl4030_codec_audio_data {
--
1.6.6.1
@@ -1,164 +0,0 @@
From 3ceb224732230934aba7d082f3e2ca96c14a9ca0 Mon Sep 17 00:00:00 2001
From: Lesly A M <leslyam@ti.com>
Date: Wed, 1 Jun 2011 14:56:56 -0700
Subject: [PATCH 11/13] MFD: TWL4030: TWL version checking
Added API to get the TWL5030 Si version from the IDCODE register.
It is used for enabling the workaround for TWL erratum 27.
Signed-off-by: Lesly A M <leslyam@ti.com>
Cc: Nishanth Menon <nm@ti.com>
Cc: David Derrick <dderrick@ti.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/twl-core.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/i2c/twl.h | 17 ++++++++++++-
2 files changed, 78 insertions(+), 1 deletions(-)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 9096d7d..a60601d 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -251,6 +251,9 @@
/* is driver active, bound to a chip? */
static bool inuse;
+/* TWL IDCODE Register value */
+static u32 twl_idcode;
+
static unsigned int twl_id;
unsigned int twl_rev(void)
{
@@ -509,6 +512,58 @@ EXPORT_SYMBOL(twl_i2c_read_u8);
/*----------------------------------------------------------------------*/
+/**
+ * twl_read_idcode_register - API to read the IDCODE register.
+ *
+ * Unlocks the IDCODE register and read the 32 bit value.
+ */
+static int twl_read_idcode_register(void)
+{
+ int err;
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK,
+ REG_UNLOCK_TEST_REG);
+ if (err) {
+ pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err);
+ goto fail;
+ }
+
+ err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode),
+ REG_IDCODE_7_0, 4);
+ if (err) {
+ pr_err("TWL4030: unable to read IDCODE -%d\n", err);
+ goto fail;
+ }
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG);
+ if (err)
+ pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err);
+fail:
+ return err;
+}
+
+/**
+ * twl_get_type - API to get TWL Si type.
+ *
+ * Api to get the TWL Si type from IDCODE value.
+ */
+int twl_get_type(void)
+{
+ return TWL_SIL_TYPE(twl_idcode);
+}
+EXPORT_SYMBOL_GPL(twl_get_type);
+
+/**
+ * twl_get_version - API to get TWL Si version.
+ *
+ * Api to get the TWL Si version from IDCODE value.
+ */
+int twl_get_version(void)
+{
+ return TWL_SIL_REV(twl_idcode);
+}
+EXPORT_SYMBOL_GPL(twl_get_version);
+
static struct device *
add_numbered_child(unsigned chip, const char *name, int num,
void *pdata, unsigned pdata_len,
@@ -1071,6 +1126,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
unsigned i;
struct twl4030_platform_data *pdata = client->dev.platform_data;
u8 temp;
+ int ret = 0;
if (!pdata) {
dev_dbg(&client->dev, "no platform data?\n");
@@ -1117,6 +1173,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* setup clock framework */
clocks_init(&client->dev, pdata->clock);
+ /* read TWL IDCODE Register */
+ if (twl_id == TWL4030_CLASS_ID) {
+ ret = twl_read_idcode_register();
+ WARN(ret < 0, "Error: reading twl_idcode register value\n");
+ }
+
/* load power event scripts */
if (twl_has_power() && pdata->power)
twl4030_power_init(pdata->power);
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index f343974..23ec058 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -151,7 +151,12 @@
#define MMC_PU (0x1 << 3)
#define MMC_PD (0x1 << 2)
-
+#define TWL_SIL_TYPE(rev) ((rev) & 0x00FFFFFF)
+#define TWL_SIL_REV(rev) ((rev) >> 24)
+#define TWL_SIL_5030 0x09002F
+#define TWL5030_REV_1_0 0x00
+#define TWL5030_REV_1_1 0x10
+#define TWL5030_REV_1_2 0x30
#define TWL4030_CLASS_ID 0x4030
#define TWL6030_CLASS_ID 0x6030
@@ -181,6 +186,9 @@ int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
+int twl_get_type(void);
+int twl_get_version(void);
+
int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
@@ -286,7 +294,12 @@ extern struct twl4030_power_data twl4030_generic_script;
*(Use TWL_4030_MODULE_INTBR)
*/
+#define REG_IDCODE_7_0 0x00
+#define REG_IDCODE_15_8 0x01
+#define REG_IDCODE_16_23 0x02
+#define REG_IDCODE_31_24 0x03
#define REG_GPPUPDCTR1 0x0F
+#define REG_UNLOCK_TEST_REG 0x12
/*I2C1 and I2C4(SR) SDA/SCL pull-up control bits */
@@ -295,6 +308,8 @@ extern struct twl4030_power_data twl4030_generic_script;
#define SR_I2C_SCL_CTRL_PU BIT(4)
#define SR_I2C_SDA_CTRL_PU BIT(6)
+#define TWL_EEPROM_R_UNLOCK 0x49
+
/*----------------------------------------------------------------------*/
/*
--
1.6.6.1
@@ -1,341 +0,0 @@
From 0bec9f7b20e7c61e0bab93195ec39cf94f1f8e25 Mon Sep 17 00:00:00 2001
From: Lesly A M <leslyam@ti.com>
Date: Wed, 1 Jun 2011 14:57:01 -0700
Subject: [PATCH 12/13] MFD: TWL4030: workaround changes for Erratum 27
Workaround for TWL5030 Silicon Errata 27 & 28:
27 - VDD1, VDD2, may have glitches when their output value is updated.
28 - VDD1 and / or VDD2 DCDC clock may stop working when internal clock
is switched from internal to external.
Erratum 27:
If the DCDC regulators is running on their internal oscillator,
negative glitches may occur on VDD1, VDD2 output when voltage is changed.
The OMAP device may reboot if the VDD1 or VDD2 go below the
core minimum operating voltage.
WORKAROUND
Set up the TWL5030 DC-DC power supplies to use the HFCLKIN instead of
the internal oscillator.
Erratum 28:
VDD1/VDD2 clock system may hang during switching the clock source from
internal oscillator to external. VDD1/VDD2 output voltages may collapse
if clock stops.
WORKAROUND
If HFCLK is disabled in OFFMODE, modify the sleep/wakeup sequence and
setuptimes to make sure the switching will happen only when HFCLKIN is stable.
Also use the TWL5030 watchdog to safeguard the first switching from
internal oscillator to HFCLKIN during the TWL5030 init.
IMPACT
power sequence is changed.
sleep/wakeup time values will be changed.
The workaround changes are called from twl4030_power_init(), since we have to
make some i2c_read calls to check the TWL4030 version & the i2c will not be
initialized in the early stage.
This workaround is required for TWL5030 Silicon version less than ES1.2
The power script & setup time changes are recommended by TI HW team.
For more information please see:
http://omapedia.org/wiki/TWL4030_power_scripts
Changes taken from TWL4030 Erratum 27 workaround patch by Nishanth Menon.
Signed-off-by: Lesly A M <leslyam@ti.com>
Cc: Nishanth Menon <nm@ti.com>
Cc: David Derrick <dderrick@ti.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/twl4030-power.c | 79 +++++++++++++++++++
drivers/mfd/twl4030-script-omap.c | 150 +++++++++++++++++++++++++++++++++++++
include/linux/i2c/twl.h | 1 +
3 files changed, 230 insertions(+), 0 deletions(-)
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 91d5bc8..8af3fe3 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -63,6 +63,14 @@ static u8 twl4030_start_script_address = 0x2b;
#define R_MEMORY_ADDRESS PHY_TO_OFF_PM_MASTER(0x59)
#define R_MEMORY_DATA PHY_TO_OFF_PM_MASTER(0x5a)
+#define R_VDD1_OSC 0x5C
+#define R_VDD2_OSC 0x6A
+#define R_VIO_OSC 0x52
+#define EXT_FS_CLK_EN BIT(6)
+
+#define R_WDT_CFG 0x03
+#define WDT_WRK_TIMEOUT 0x03
+
/* resource configuration registers
<RESOURCE>_DEV_GRP at address 'n+0'
<RESOURCE>_TYPE at address 'n+1'
@@ -512,6 +520,67 @@ int twl4030_remove_script(u8 flags)
}
EXPORT_SYMBOL_GPL(twl4030_remove_script);
+/**
+ * twl_dcdc_use_hfclk - API to use HFCLK for TWL DCDCs
+ *
+ * TWL DCDCs switching to HFCLK instead of using internal RC oscillator.
+ */
+static int twl_dcdc_use_hfclk(void)
+{
+ u8 val;
+ u8 smps_osc_reg[] = {R_VDD1_OSC, R_VDD2_OSC, R_VIO_OSC};
+ int i;
+ int err;
+
+ for (i = 0; i < sizeof(smps_osc_reg); i++) {
+ err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &val,
+ smps_osc_reg[i]);
+ val |= EXT_FS_CLK_EN;
+ err |= twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val,
+ smps_osc_reg[i]);
+ }
+ return err;
+}
+
+/**
+ * twl_erratum27_workaround - Workaround for TWL5030 Silicon Erratum 27
+ * 27 - VDD1, VDD2, may have glitches when their output value is updated.
+ * 28 - VDD1 and / or VDD2 DCDC clock may stop working when internal clock is
+ * switched from internal to external.
+ *
+ * Workaround requires the TWL DCDCs to use HFCLK instead of
+ * internal oscillator. Also enable TWL watchdog before switching the osc
+ * to recover if the VDD1/VDD2 stop working.
+ */
+static void twl_erratum27_workaround(void)
+{
+ u8 wdt_counter_val = 0;
+ int err;
+
+ /* Setup the twl wdt to take care of borderline failure case */
+ err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &wdt_counter_val,
+ R_WDT_CFG);
+ err |= twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, WDT_WRK_TIMEOUT,
+ R_WDT_CFG);
+
+ /* TWL DCDC switching to HFCLK */
+ err |= twl_dcdc_use_hfclk();
+
+ /* restore the original value */
+ err |= twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, wdt_counter_val,
+ R_WDT_CFG);
+ if (err)
+ pr_warning("TWL4030: workaround setup failed!\n");
+}
+
+static bool is_twl5030_erratum27wa_required(void)
+{
+ if (twl_get_type() == TWL_SIL_5030)
+ return (twl_get_version() < TWL5030_REV_1_2);
+
+ return 0;
+}
+
int twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
{
int err = 0;
@@ -530,6 +599,16 @@ int twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)
goto unlock;
+
+ /* Applying TWL5030 Erratum 27 WA based on Si revision &
+ * flag updated from board file*/
+ if (is_twl5030_erratum27wa_required()) {
+ pr_info("TWL5030: Enabling workaround for Si Erratum 27\n");
+ twl_erratum27_workaround();
+ if (twl4030_scripts->twl5030_erratum27wa_script)
+ twl4030_scripts->twl5030_erratum27wa_script();
+ }
+
for (i = 0; i < twl4030_scripts->num; i++) {
err = load_twl4030_script(twl4030_scripts->scripts[i], address);
if (err)
diff --git a/drivers/mfd/twl4030-script-omap.c b/drivers/mfd/twl4030-script-omap.c
index 867a442..ff93fd2 100644
--- a/drivers/mfd/twl4030-script-omap.c
+++ b/drivers/mfd/twl4030-script-omap.c
@@ -326,10 +326,160 @@ static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
{ 0, 0},
};
+/*
+ * Sleep and active sequences with changes for TWL5030 Erratum 27 workaround
+ *
+ * Sysoff (using sys_off signal):
+ * When SYS_CLKREQ goes low during retention no resources will be affected
+ * since no resources are assigned to P3 only.
+ *
+ * Since all resources are assigned to P1 and P3 then all resources
+ * will be affected on the falling edge of P3 (SYS_CLKREQ).
+ * When OMAP lower the SYS_CLKREQ signal PMIC will execute the
+ * A2S sequence in which HFCLKOUT is dissabled first and
+ * after 488.32 usec(PRM_VOLTOFFSET) resources assigned to P1 and P3
+ * and of TYPE2=1 are put to sleep
+ * (VDD1, VDD2, VPLL1, REGEN, NRESPWRON & SYSEN).
+ * Again after a 61.04 usec resources assigned to P1 and P3
+ * and of TYPE2=2 are put to sleep
+ * (VINTANA1, VINTANA2, VINTDIG, VIO & CLKEN).
+ *
+ * On wakeup event OMAP goes active and pulls the SYS_CLKREQ high,
+ * and will execute the S2A sequence which is same for P1_P2 & P3.
+ * This will turn on all resources of TYPE2=2 to go to the active state.
+ * Three dummy broadcast messages are added to get a delay of ~10 ms
+ * before enabling the HFCLKOUT resource. And after a 30.52 usec
+ * all resources of TYPE2=1 are put to the active state.
+ *
+ * This 10ms delay can be reduced if the oscillator is having less
+ * stabilization time. A should be taken care if it needs more time
+ * for stabilization.
+ *
+ */
+
+/**
+ * DOC: Sleep to Active sequence for P1/P2/P3
+ *
+ * The wakeup sequence is adjusted to do the VDD1/VDD2 voltage ramp-up
+ * only after HFCLKIN is stabilized and the HFCLKOUT is enabled.
+ */
+static struct twl4030_ins wakeup_seq_erratum27[] __initdata = {
+ /*
+ * Broadcast message to put res(TYPE2 = 2) to active.
+ * Wait for ~10 mS (ramp-up time for OSC on the board)
+ * after HFCLKIN is enabled
+ */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2,
+ RES_STATE_ACTIVE), 55},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2,
+ RES_STATE_ACTIVE), 55},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2,
+ RES_STATE_ACTIVE), 54},
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2,
+ RES_STATE_ACTIVE), 1},
+ /* Singular message to enable HCLKOUT after HFCLKIN is stabilized */
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_HFCLKOUT, RES_STATE_ACTIVE), 1},
+ /*
+ * Broadcast message to put res(TYPE2 = 1) to active.
+ * VDD1/VDD2 ramp-up after HFCLKIN is stable and HFCLKOUT is enabled.
+ */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1,
+ RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_script_erratum27 __initdata = {
+ .script = wakeup_seq_erratum27,
+ .size = ARRAY_SIZE(wakeup_seq_erratum27),
+ .flags = TWL4030_WAKEUP12_SCRIPT | TWL4030_WAKEUP3_SCRIPT,
+};
+
+/**
+ * DOC: Active to Sleep sequence for P1/P2/P3
+ *
+ * The sleep sequence is adjusted to do the switching of VDD1/VDD2/VIO OSC from
+ * HFCLKIN to internal oscillator when the HFCLKIN is stable.
+ */
+static struct twl4030_ins sleep_on_seq_erratum27[] __initdata = {
+ /*
+ * Singular message to disable HCLKOUT.
+ * Wait for ~488.32 uS to do the switching of VDD1/VDD2/VIO OSC from
+ * HFCLKIN to internal oscillator before disabling HFCLKIN.
+ */
+ {MSG_SINGULAR(DEV_GRP_NULL, RES_HFCLKOUT, RES_STATE_SLEEP), 20},
+ /* Broadcast message to put res(TYPE2 = 1) to sleep */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1,
+ RES_STATE_SLEEP), 2},
+ /* Broadcast message to put res(TYPE2 = 2) to sleep, disable HFCLKIN */
+ {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2,
+ RES_STATE_SLEEP), 2},
+};
+
+static struct twl4030_script sleep_on_script_erratum27 __initdata = {
+ .script = sleep_on_seq_erratum27,
+ .size = ARRAY_SIZE(sleep_on_seq_erratum27),
+ .flags = TWL4030_SLEEP_SCRIPT,
+};
+
+/* TWL4030 script for sleep, wakeup & warm_reset */
+static struct twl4030_script *twl4030_scripts_erratum27[] __initdata = {
+ &wakeup_script_erratum27,
+ &sleep_on_script_erratum27,
+ &wrst_script,
+};
+
+/**
+ * DOC: TWL4030 resource configuration
+ *
+ * VDD1/VDD2/VPLL are assigned to P1 and P3, to have better control
+ * during OFFMODE. HFCLKOUT is assigned to P1 and P3 (*p2) to turn off
+ * only during OFFMODE.
+ * (*P2 is included if the platform uses it for modem/some other processor)
+ */
+static struct twl4030_resconfig twl4030_rconfig_erratum27[] __initdata = {
+ { .resource = RES_VPLL1, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = 3, .type2 = 1, .remap_sleep = RES_STATE_OFF },
+ { .resource = RES_VINTANA1, .devgroup = DEV_GRP_ALL, .type = 1,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_VINTANA2, .devgroup = DEV_GRP_ALL, .type = 0,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_VINTDIG, .devgroup = DEV_GRP_ALL, .type = 1,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_VIO, .devgroup = DEV_GRP_ALL, .type = 2,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_VDD1, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = 4, .type2 = 1, .remap_sleep = RES_STATE_OFF },
+ { .resource = RES_VDD2, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = 3, .type2 = 1, .remap_sleep = RES_STATE_OFF },
+ { .resource = RES_REGEN, .devgroup = DEV_GRP_ALL, .type = 2,
+ .type2 = 1, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_NRES_PWRON, .devgroup = DEV_GRP_ALL, .type = 0,
+ .type2 = 1, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_CLKEN, .devgroup = DEV_GRP_ALL, .type = 3,
+ .type2 = 2, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_SYSEN, .devgroup = DEV_GRP_ALL, .type = 6,
+ .type2 = 1, .remap_sleep = RES_STATE_SLEEP },
+ { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P1 | DEV_GRP_P3,
+ .type = 0, .type2 = 1, .remap_sleep = RES_STATE_SLEEP },
+ { 0, 0},
+};
+
+/**
+ * twl5030_script_erratum27() - API to modify TWL4030 script
+ *
+ * Updating the TWL4030 script & resource configuration
+ */
+static void __init twl5030_script_erratum27(void)
+{
+ twl4030_generic_script.scripts = twl4030_scripts_erratum27;
+ twl4030_generic_script.num = ARRAY_SIZE(twl4030_scripts_erratum27);
+ twl4030_generic_script.resource_config = twl4030_rconfig_erratum27;
+}
+
struct twl4030_power_data twl4030_generic_script __initdata = {
.scripts = twl4030_scripts,
.num = ARRAY_SIZE(twl4030_scripts),
.resource_config = twl4030_rconfig,
+ .twl5030_erratum27wa_script = twl5030_script_erratum27,
};
static int __init twl4030_script_probe(struct platform_device *pdev)
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 23ec058..10cb6e2 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -681,6 +681,7 @@ struct twl4030_power_data {
struct twl4030_script **scripts;
unsigned num;
struct twl4030_resconfig *resource_config;
+ void (*twl5030_erratum27wa_script)(void);
#define TWL4030_RESCONFIG_UNDEF ((u8)-1)
};
--
1.6.6.1
@@ -1,184 +0,0 @@
From bf171753a162d07753208c6bcfae8ca1e5c94af3 Mon Sep 17 00:00:00 2001
From: Lesly A M <leslyam@ti.com>
Date: Wed, 1 Jun 2011 14:57:05 -0700
Subject: [PATCH 13/13] MFD: TWL4030: optimizing resource configuration
Skip the i2c register writes in twl4030_configure_resource() if the new value
is same as the old value, for devgrp/type/remap regs.
Suggested by David Derrick <dderrick@ti.com>
Signed-off-by: Lesly A M <leslyam@ti.com>
Cc: Nishanth Menon <nm@ti.com>
Cc: David Derrick <dderrick@ti.com>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
drivers/mfd/twl4030-power.c | 126 ++++++++++++++++++++++++------------------
1 files changed, 72 insertions(+), 54 deletions(-)
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 8af3fe3..d82632f 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -335,9 +335,9 @@ static int twl4030_configure_resource(struct twl4030_resconfig *rconfig)
{
int rconfig_addr;
int err;
- u8 type;
- u8 grp;
- u8 remap;
+ u8 type, type_value;
+ u8 grp, grp_value;
+ u8 remap, remap_value;
if (rconfig->resource > TOTAL_RESOURCES) {
pr_err("TWL4030 Resource %d does not exist\n",
@@ -348,76 +348,94 @@ static int twl4030_configure_resource(struct twl4030_resconfig *rconfig)
rconfig_addr = res_config_addrs[rconfig->resource];
/* Set resource group */
- err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
+ if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
+ err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &grp,
rconfig_addr + DEV_GRP_OFFSET);
- if (err) {
- pr_err("TWL4030 Resource %d group could not be read\n",
- rconfig->resource);
- return err;
- }
+ if (err) {
+ pr_err("TWL4030 Resource %d group could not be read\n",
+ rconfig->resource);
+ return err;
+ }
- if (rconfig->devgroup != TWL4030_RESCONFIG_UNDEF) {
- grp &= ~DEV_GRP_MASK;
- grp |= rconfig->devgroup << DEV_GRP_SHIFT;
- err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ grp_value = (grp & DEV_GRP_MASK) >> DEV_GRP_SHIFT;
+
+ if (rconfig->devgroup != grp_value) {
+ grp &= ~DEV_GRP_MASK;
+ grp |= rconfig->devgroup << DEV_GRP_SHIFT;
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
grp, rconfig_addr + DEV_GRP_OFFSET);
- if (err < 0) {
- pr_err("TWL4030 failed to program devgroup\n");
- return err;
+ if (err < 0) {
+ pr_err("TWL4030 failed to program devgroup\n");
+ return err;
+ }
}
}
/* Set resource types */
- err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
+ if ((rconfig->type != TWL4030_RESCONFIG_UNDEF) ||
+ (rconfig->type2 != TWL4030_RESCONFIG_UNDEF)) {
+
+ err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &type,
rconfig_addr + TYPE_OFFSET);
- if (err < 0) {
- pr_err("TWL4030 Resource %d type could not be read\n",
- rconfig->resource);
- return err;
- }
+ if (err < 0) {
+ pr_err("TWL4030 Resource %d type could not be read\n",
+ rconfig->resource);
+ return err;
+ }
- if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
- type &= ~TYPE_MASK;
- type |= rconfig->type << TYPE_SHIFT;
- }
+ type_value = type;
- if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
- type &= ~TYPE2_MASK;
- type |= rconfig->type2 << TYPE2_SHIFT;
- }
+ if (rconfig->type != TWL4030_RESCONFIG_UNDEF) {
+ type &= ~TYPE_MASK;
+ type |= rconfig->type << TYPE_SHIFT;
+ }
- err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ if (rconfig->type2 != TWL4030_RESCONFIG_UNDEF) {
+ type &= ~TYPE2_MASK;
+ type |= rconfig->type2 << TYPE2_SHIFT;
+ }
+
+ if (type != type_value) {
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
type, rconfig_addr + TYPE_OFFSET);
- if (err < 0) {
- pr_err("TWL4030 failed to program resource type\n");
- return err;
+ if (err < 0) {
+ pr_err("TWL4030 failed to program resource type\n");
+ return err;
+ }
+ }
}
/* Set remap states */
- err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap,
+ if ((rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) ||
+ (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF)) {
+ err = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &remap,
rconfig_addr + REMAP_OFFSET);
- if (err < 0) {
- pr_err("TWL4030 Resource %d remap could not be read\n",
- rconfig->resource);
- return err;
- }
+ if (err < 0) {
+ pr_err("TWL4030 Resource %d remap could not be read\n",
+ rconfig->resource);
+ return err;
+ }
- if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
- remap &= ~OFF_STATE_MASK;
- remap |= rconfig->remap_off << OFF_STATE_SHIFT;
- }
+ remap_value = remap;
- if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
- remap &= ~SLEEP_STATE_MASK;
- remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT;
- }
+ if (rconfig->remap_off != TWL4030_RESCONFIG_UNDEF) {
+ remap &= ~OFF_STATE_MASK;
+ remap |= rconfig->remap_off << OFF_STATE_SHIFT;
+ }
- err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
- remap,
- rconfig_addr + REMAP_OFFSET);
- if (err < 0) {
- pr_err("TWL4030 failed to program remap\n");
- return err;
+ if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) {
+ remap &= ~SLEEP_STATE_MASK;
+ remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT;
+ }
+
+ if (remap != remap_value) {
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ remap, rconfig_addr + REMAP_OFFSET);
+ if (err < 0) {
+ pr_err("TWL4030 failed to program remap\n");
+ return err;
+ }
+ }
}
return 0;
--
1.6.6.1
@@ -1,121 +0,0 @@
From 2adb339e4988632379971febe5696f21d05c71f2 Mon Sep 17 00:00:00 2001
From: Anand Gadiyar <gadiyar@ti.com>
Date: Tue, 19 Jul 2011 01:52:14 -0700
Subject: [PATCH] usb: musb: Enable DMA mode1 RX for USB-Mass-Storage
This patch enables the DMA mode1 RX support.
This feature is enabled based on the short_not_ok flag passed from
gadget drivers.
This will result in a thruput performance gain of around
40% for USB mass-storage/mtp use cases.
Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
Signed-off-by: Moiz Sonasath <m-sonasath@ti.com>
Tested-by: Vikram Pandita <vikram.pandita@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
drivers/usb/musb/musb_gadget.c | 68 ++++++++++++++++++++++++---------------
1 files changed, 42 insertions(+), 26 deletions(-)
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index f47c201..ca32c63 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -630,6 +630,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
u16 len;
u16 csr = musb_readw(epio, MUSB_RXCSR);
struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
+ u8 use_mode_1;
if (hw_ep->is_shared_fifo)
musb_ep = &hw_ep->ep_in;
@@ -679,6 +680,18 @@ static void rxstate(struct musb *musb, struct musb_request *req)
if (csr & MUSB_RXCSR_RXPKTRDY) {
len = musb_readw(epio, MUSB_RXCOUNT);
+
+ /*
+ * Enable Mode 1 for RX transfers only for mass-storage
+ * use-case, based on short_not_ok flag which is set only
+ * from file_storage and f_mass_storage drivers
+ */
+
+ if (request->short_not_ok && len == musb_ep->packet_sz)
+ use_mode_1 = 1;
+ else
+ use_mode_1 = 0;
+
if (request->actual < request->length) {
#ifdef CONFIG_USB_INVENTRA_DMA
if (is_buffer_mapped(req)) {
@@ -710,37 +723,40 @@ static void rxstate(struct musb *musb, struct musb_request *req)
* then becomes usable as a runtime "use mode 1" hint...
*/
- csr |= MUSB_RXCSR_DMAENAB;
-#ifdef USE_MODE1
- csr |= MUSB_RXCSR_AUTOCLEAR;
- /* csr |= MUSB_RXCSR_DMAMODE; */
-
- /* this special sequence (enabling and then
- * disabling MUSB_RXCSR_DMAMODE) is required
- * to get DMAReq to activate
- */
- musb_writew(epio, MUSB_RXCSR,
- csr | MUSB_RXCSR_DMAMODE);
-#else
- if (!musb_ep->hb_mult &&
- musb_ep->hw_ep->rx_double_buffered)
+ /* Experimental: Mode1 works with mass storage use cases */
+ if (use_mode_1) {
csr |= MUSB_RXCSR_AUTOCLEAR;
-#endif
- musb_writew(epio, MUSB_RXCSR, csr);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ csr |= MUSB_RXCSR_DMAENAB;
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ /* this special sequence (enabling and then
+ * disabling MUSB_RXCSR_DMAMODE) is required
+ * to get DMAReq to activate
+ */
+ musb_writew(epio, MUSB_RXCSR,
+ csr | MUSB_RXCSR_DMAMODE);
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ } else {
+ if (!musb_ep->hb_mult &&
+ musb_ep->hw_ep->rx_double_buffered)
+ csr |= MUSB_RXCSR_AUTOCLEAR;
+ csr |= MUSB_RXCSR_DMAENAB;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
if (request->actual < request->length) {
int transfer_size = 0;
-#ifdef USE_MODE1
- transfer_size = min(request->length - request->actual,
- channel->max_len);
-#else
- transfer_size = min(request->length - request->actual,
- (unsigned)len);
-#endif
- if (transfer_size <= musb_ep->packet_sz)
- musb_ep->dma->desired_mode = 0;
- else
+ if (use_mode_1) {
+ transfer_size = min(request->length - request->actual,
+ channel->max_len);
musb_ep->dma->desired_mode = 1;
+ } else {
+ transfer_size = min(request->length - request->actual,
+ (unsigned)len);
+ musb_ep->dma->desired_mode = 0;
+ }
use_dma = c->channel_program(
channel,
--
1.6.6.1
@@ -1,13 +0,0 @@
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index c541093..c4744e1 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -87,7 +87,7 @@
#define NFS_ROOT "/tftpboot/%s"
/* Default NFSROOT mount options. */
-#define NFS_DEF_OPTIONS "udp"
+#define NFS_DEF_OPTIONS "vers=2,udp,rsize=4096,wsize=4096"
/* Parameters passed from the kernel command line */
static char nfs_root_parms[256] __initdata = "";
@@ -1,38 +0,0 @@
From 38dd5aadc86725f6018d23679e9daa60ca0a8319 Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Thu, 12 May 2011 07:59:52 -0500
Subject: [PATCH 1/6] OMAP2+: cpufreq: free up table on exit
freq_table allocated by opp_init_cpufreq_table in omap_cpu_init
needs to be freed in omap_cpu_exit.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/omap2plus-cpufreq.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index d53ce23..e38ebb8 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -26,6 +26,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/opp.h>
+#include <linux/slab.h>
#include <linux/cpu.h>
#include <asm/system.h>
@@ -216,6 +217,8 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
static int omap_cpu_exit(struct cpufreq_policy *policy)
{
clk_exit_cpufreq_table(&freq_table);
+ kfree(freq_table);
+ freq_table = NULL;
clk_put(mpu_clk);
return 0;
}
--
1.6.6.1
@@ -1,44 +0,0 @@
From 5febdc0482e545c2a598f035c5e03931e0c3c808 Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Thu, 12 May 2011 08:14:41 -0500
Subject: [PATCH 2/6] OMAP2+: cpufreq: handle invalid cpufreq table
Handle the case when cpufreq_frequency_table_cpuinfo fails. freq_table
that we passed failed the internal test of cpufreq generic driver,
so we should'nt be using the freq_table as such. Instead, warn and
fallback to clock functions for validation and operation.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/omap2plus-cpufreq.c | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index e38ebb8..6e3666a 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -182,10 +182,18 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
if (freq_table) {
result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
- if (!result)
+ if (!result) {
cpufreq_frequency_table_get_attr(freq_table,
policy->cpu);
- } else {
+ } else {
+ WARN(true, "%s: fallback to clk_round(freq_table=%d)\n",
+ __func__, result);
+ kfree(freq_table);
+ freq_table = NULL;
+ }
+ }
+
+ if (!freq_table) {
policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
VERY_HI_RATE) / 1000;
--
1.6.6.1
@@ -1,33 +0,0 @@
From aef7e862873e6125159a18d22a2e37b1fbab2153 Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Thu, 12 May 2011 16:27:45 -0700
Subject: [PATCH 3/6] OMAP2+: cpufreq: minor comment cleanup
this should probably get squashed in..
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/omap2plus-cpufreq.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index 6e3666a..45f1e9e 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -84,8 +84,10 @@ static int omap_target(struct cpufreq_policy *policy,
if (is_smp() && (num_online_cpus() < NR_CPUS))
return ret;
- /* Ensure desired rate is within allowed range. Some govenors
- * (ondemand) will just pass target_freq=0 to get the minimum. */
+ /*
+ * Ensure desired rate is within allowed range. Some govenors
+ * (ondemand) will just pass target_freq=0 to get the minimum.
+ */
if (target_freq < policy->min)
target_freq = policy->min;
if (target_freq > policy->max)
--
1.6.6.1
@@ -1,48 +0,0 @@
From f231980dbd0f05229f2020e59b7242872576416f Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Fri, 13 May 2011 05:34:35 -0700
Subject: [PATCH 4/6] OMAP2: cpufreq: use clk_init_cpufreq_table if OPPs not available
OMAP2 does not use OPP tables at the moment for DVFS. Currently,
we depend on opp table initialization to give us the freq_table,
which makes sense for OMAP3+. for OMAP2, we should be using
clk_init_cpufreq_table - so if the opp based frequency table
initilization fails, fall back to clk_init_cpufreq_table to give
us the table.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/omap2plus-cpufreq.c | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index 45f1e9e..854f4b3 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -180,7 +180,13 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
pr_warning("%s: unable to get the mpu device\n", __func__);
return -EINVAL;
}
- opp_init_cpufreq_table(mpu_dev, &freq_table);
+
+ /*
+ * if we dont get cpufreq table using opp, use traditional omap2 lookup
+ * as a fallback
+ */
+ if (opp_init_cpufreq_table(mpu_dev, &freq_table))
+ clk_init_cpufreq_table(&freq_table);
if (freq_table) {
result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
@@ -188,6 +194,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(freq_table,
policy->cpu);
} else {
+ clk_exit_cpufreq_table(&freq_table);
WARN(true, "%s: fallback to clk_round(freq_table=%d)\n",
__func__, result);
kfree(freq_table);
--
1.6.6.1
@@ -1,78 +0,0 @@
From 272d76bcb22b9509ccc1b59d3a62e3930d902d17 Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Fri, 13 May 2011 05:43:49 -0700
Subject: [PATCH 5/6] OMAP2+: cpufreq: use cpufreq_frequency_table_target
Use cpufreq_frequency_table_target for finding the proper target
instead of seeing if the frequency requested is divisible alone.
if we have a frequency table, we should restrict ourselves to
selecting the "approved" frequencies alone and only in the case
where the frequency table is not available should we attempt at
closest roundable clock frequency.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/omap2plus-cpufreq.c | 38 ++++++++++++++++++++++--------
1 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index 854f4b3..d0b4f97 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -77,24 +77,42 @@ static int omap_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
- int i, ret = 0;
+ unsigned int i;
+ int ret = 0;
struct cpufreq_freqs freqs;
/* Changes not allowed until all CPUs are online */
if (is_smp() && (num_online_cpus() < NR_CPUS))
return ret;
- /*
- * Ensure desired rate is within allowed range. Some govenors
- * (ondemand) will just pass target_freq=0 to get the minimum.
- */
- if (target_freq < policy->min)
- target_freq = policy->min;
- if (target_freq > policy->max)
- target_freq = policy->max;
+ if (freq_table) {
+ ret = cpufreq_frequency_table_target(policy, freq_table,
+ target_freq, relation, &i);
+ if (ret) {
+ pr_debug("%s: cpu%d: no freq match for %d(ret=%d)\n",
+ __func__, policy->cpu, target_freq, ret);
+ return ret;
+ }
+ freqs.new = freq_table[i].frequency;
+ } else {
+ /*
+ * Ensure desired rate is within allowed range. Some govenors
+ * (ondemand) will just pass target_freq=0 to get the minimum.
+ */
+ if (target_freq < policy->min)
+ target_freq = policy->min;
+ if (target_freq > policy->max)
+ target_freq = policy->max;
+
+ freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
+ }
+ if (!freqs.new) {
+ pr_err("%s: cpu%d: no match for freq %d\n", __func__,
+ policy->cpu, target_freq);
+ return -EINVAL;
+ }
freqs.old = omap_getspeed(policy->cpu);
- freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
freqs.cpu = policy->cpu;
if (freqs.old == freqs.new)
--
1.6.6.1
@@ -1,100 +0,0 @@
From 42a384af80e07534913d9002ec8d9caf5d4d305c Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Wed, 18 May 2011 01:48:23 -0500
Subject: [PATCH 6/6] OMAP2+: cpufreq: fix freq_table leak
Since we have two cpus the cpuinit call for cpu1 causes
freq_table of cpu0 to be overwritten. instead, we maintain
a counter to keep track of cpus who use the cpufreq table
allocate it once(one freq table for all CPUs) and free them
once the last user is done with it.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/omap2plus-cpufreq.c | 33 ++++++++++++++++++++++++------
1 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index d0b4f97..fc3d0fb 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -42,6 +42,9 @@
#define VERY_HI_RATE 900000000
static struct cpufreq_frequency_table *freq_table;
+static int freq_table_users;
+static DEFINE_MUTEX(freq_table_lock);
+
static struct clk *mpu_clk;
static int omap_verify_speed(struct cpufreq_policy *policy)
@@ -172,6 +175,18 @@ skip_lpj:
return ret;
}
+static void freq_table_free(void)
+{
+ if (!freq_table_users)
+ return;
+ freq_table_users--;
+ if (freq_table_users)
+ return;
+ clk_exit_cpufreq_table(&freq_table);
+ kfree(freq_table);
+ freq_table = NULL;
+}
+
static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
@@ -199,14 +214,18 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
return -EINVAL;
}
+ mutex_lock(&freq_table_lock);
/*
* if we dont get cpufreq table using opp, use traditional omap2 lookup
* as a fallback
*/
- if (opp_init_cpufreq_table(mpu_dev, &freq_table))
- clk_init_cpufreq_table(&freq_table);
+ if (!freq_table) {
+ if (opp_init_cpufreq_table(mpu_dev, &freq_table))
+ clk_init_cpufreq_table(&freq_table);
+ }
if (freq_table) {
+ freq_table_users++;
result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
if (!result) {
cpufreq_frequency_table_get_attr(freq_table,
@@ -215,10 +234,10 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
clk_exit_cpufreq_table(&freq_table);
WARN(true, "%s: fallback to clk_round(freq_table=%d)\n",
__func__, result);
- kfree(freq_table);
- freq_table = NULL;
+ freq_table_free();
}
}
+ mutex_unlock(&freq_table_lock);
if (!freq_table) {
policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
@@ -251,9 +270,9 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
static int omap_cpu_exit(struct cpufreq_policy *policy)
{
- clk_exit_cpufreq_table(&freq_table);
- kfree(freq_table);
- freq_table = NULL;
+ mutex_lock(&freq_table_lock);
+ freq_table_free();
+ mutex_unlock(&freq_table_lock);
clk_put(mpu_clk);
return 0;
}
--
1.6.6.1
@@ -1,134 +0,0 @@
From 8726f3a7218b72a1003904a24bb000b3e4f9b4d1 Mon Sep 17 00:00:00 2001
From: Mike Turquette <mturquette@ti.com>
Date: Tue, 17 May 2011 09:35:54 -0500
Subject: [PATCH 1/2] cpufreq: helpers for walking the frequency table
Two new functions for getting the next higher and next lower frequencies
in the cpufreq table, based upon a frequency supplied in kHz.
This is useful for cpufreq governors that do not target frequencies
based upon a percentage or a pre-determined value, but instead access
the cpufreq table directly.
Signed-off-by: Mike Turquette <mturquette@ti.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
drivers/cpufreq/freq_table.c | 73 ++++++++++++++++++++++++++++++++++++++++++
include/linux/cpufreq.h | 9 +++++
2 files changed, 82 insertions(+), 0 deletions(-)
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 0543221..11a307b 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
+#include <linux/err.h>
#define dprintk(msg...) \
cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
@@ -174,6 +175,78 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
+int cpufreq_frequency_table_next_lowest(struct cpufreq_policy *policy,
+ struct cpufreq_frequency_table *table, int *index)
+{
+ unsigned int cur_freq;
+ unsigned int next_lowest_freq;
+ int optimal_index = -1;
+ int i = 0;
+
+ if (!policy || IS_ERR(policy) || !table || IS_ERR(table) ||
+ !index || IS_ERR(index))
+ return -ENOMEM;
+
+ cur_freq = policy->cur;
+ next_lowest_freq = policy->min;
+
+ /* we're at the lowest frequency in the table already, bail out */
+ if (cur_freq == policy->min)
+ return -EINVAL;
+
+ /* walk the list, find closest freq to cur_freq that is below it */
+ while(table[i].frequency != CPUFREQ_TABLE_END) {
+ if (table[i].frequency < cur_freq &&
+ table[i].frequency >= next_lowest_freq) {
+ next_lowest_freq = table[i].frequency;
+ optimal_index = table[i].index;
+ }
+
+ i++;
+ }
+
+ *index = optimal_index;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_frequency_table_next_lowest);
+
+int cpufreq_frequency_table_next_highest(struct cpufreq_policy *policy,
+ struct cpufreq_frequency_table *table, int *index)
+{
+ unsigned int cur_freq;
+ unsigned int next_higher_freq;
+ int optimal_index = -1;
+ int i = 0;
+
+ if (!policy || IS_ERR(policy) || !table || IS_ERR(table) ||
+ !index || IS_ERR(index))
+ return -ENOMEM;
+
+ cur_freq = policy->cur;
+ next_higher_freq = policy->max;
+
+ /* we're at the highest frequency in the table already, bail out */
+ if (cur_freq == policy->max)
+ return -EINVAL;
+
+ /* walk the list, find closest freq to cur_freq that is above it */
+ while(table[i].frequency != CPUFREQ_TABLE_END) {
+ if (table[i].frequency > cur_freq &&
+ table[i].frequency <= next_higher_freq) {
+ next_higher_freq = table[i].frequency;
+ optimal_index = table[i].index;
+ }
+
+ i++;
+ }
+
+ *index = optimal_index;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_frequency_table_next_highest);
+
static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
/**
* show_available_freqs - show available frequencies for the specified CPU
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 9343dd3..a38fca8 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -396,6 +396,15 @@ void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
void cpufreq_frequency_table_put_attr(unsigned int cpu);
+/* the following are for use in governors, or anywhere else */
+extern int cpufreq_frequency_table_next_lowest(struct cpufreq_policy *policy,
+ struct cpufreq_frequency_table *table,
+ int *index);
+
+extern int cpufreq_frequency_table_next_highest(struct cpufreq_policy *policy,
+ struct cpufreq_frequency_table *table,
+ int *index);
+
/*********************************************************************
* UNIFIED DEBUG HELPERS *
--
1.6.6.1
@@ -1,879 +0,0 @@
From e4c777d8314d7925e4895f00b3a7ebd64a4d830b Mon Sep 17 00:00:00 2001
From: Mike Turquette <mturquette@ti.com>
Date: Tue, 17 May 2011 09:43:09 -0500
Subject: [PATCH 2/2] cpufreq: introduce hotplug governor
The "hotplug" governor scales CPU frequency based on load, similar to
"ondemand". It scales up to the highest frequency when "up_threshold"
is crossed and scales down one frequency at a time when "down_threshold"
is crossed. Unlike those governors, target frequencies are determined
by directly accessing the CPUfreq frequency table, instead of taking
some percentage of maximum available frequency.
The key difference in the "hotplug" governor is that it will disable
auxillary CPUs when the system is very idle, and enable them again once
the system becomes busy. This is achieved by averaging load over
multiple sampling periods; if CPUs were online or offlined based on a
single sampling period then thrashing will occur.
Sysfs entries exist for "hotplug_in_sampling_periods" and for
"hotplug_out_sampling_periods" which determine how many consecutive
periods get averaged to determine if auxillery CPUs should be onlined or
offlined. Defaults are 5 periods and 20 periods respectively.
Otherwise the standard sysfs entries you might find for "ondemand" and
"conservative" governors are there.
To use this governor it is assumed that your CPUfreq driver has
populated the CPUfreq table, CONFIG_NO_HZ is enabled and
CONFIG_HOTPLUG_CPU is enabled.
Changes in V2:
Corrected default sampling periods
Optimized load history array resizing
Maintain load history when resizing array
Add locking to dbs_check_cpu
Switch from enable_nonboot_cpus to cpu_up
Switch from disable_nonboot_cpus to down_cpu
Fix some printks
Coding style around for-loops
Signed-off-by: Mike Turquette <mturquette@ti.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
Documentation/cpu-freq/governors.txt | 28 ++
drivers/cpufreq/Kconfig | 33 ++
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/cpufreq_hotplug.c | 705 ++++++++++++++++++++++++++++++++++
include/linux/cpufreq.h | 3 +
5 files changed, 770 insertions(+), 0 deletions(-)
create mode 100644 drivers/cpufreq/cpufreq_hotplug.c
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
index e74d0a2..c2e3d3d 100644
--- a/Documentation/cpu-freq/governors.txt
+++ b/Documentation/cpu-freq/governors.txt
@@ -193,6 +193,34 @@ governor but for the opposite direction. For example when set to its
default value of '20' it means that if the CPU usage needs to be below
20% between samples to have the frequency decreased.
+
+2.6 Hotplug
+-----------
+
+The CPUfreq governor "hotplug" operates similary to "ondemand" and
+"conservative". It's decisions are based primarily on CPU load. Like
+"ondemand" the "hotplug" governor will ramp up to the highest frequency
+once the run-time tunable "up_threshold" parameter is crossed. Like
+"conservative", the "hotplug" governor exports a "down_threshold"
+parameter that is also tunable at run-time. When the "down_threshold"
+is crossed the CPU transitions to the next lowest frequency in the
+CPUfreq frequency table instead of decrementing the frequency based on a
+percentage of maximum load.
+
+The main reason "hotplug" governor exists is for architectures requiring
+that only the master CPU be online in order to hit low-power states
+(C-states). OMAP4 is one such example of this. The "hotplug" governor
+is also helpful in reducing thermal output in devices with tight thermal
+constraints.
+
+Auxillary CPUs are onlined/offline based on CPU load, but the decision
+to do so is made after averaging several sampling windows. This is to
+reduce CPU hotplug "thrashing", which can be caused by normal system
+entropy and leads to lots of spurious plug-in and plug-out transitions.
+The number of sampling periods averaged together is tunable via the
+"hotplug_in_sampling_periods" and "hotplug_out_sampling_periods"
+run-time tunable parameters.
+
3. The Governor Interface in the CPUfreq Core
=============================================
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index ca8ee80..c716a0e 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -110,6 +110,19 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
Be aware that not all cpufreq drivers support the conservative
governor. If unsure have a look at the help section of the
driver. Fallback governor will be the performance governor.
+
+config CPU_FREQ_DEFAULT_GOV_HOTPLUG
+ bool "hotplug"
+ select CPU_FREQ_GOV_HOTPLUG
+ select CPU_FREQ_GOV_PERFORMANCE
+ help
+ Use the CPUFreq governor 'hotplug' as default. This allows you
+ to get a full dynamic frequency capable system with CPU
+ hotplug support by simply loading your cpufreq low-level
+ hardware driver. Be aware that not all cpufreq drivers
+ support the hotplug governor. If unsure have a look at
+ the help section of the driver. Fallback governor will be the
+ performance governor.
endchoice
config CPU_FREQ_GOV_PERFORMANCE
@@ -190,4 +203,24 @@ config CPU_FREQ_GOV_CONSERVATIVE
If in doubt, say N.
+config CPU_FREQ_GOV_HOTPLUG
+ tristate "'hotplug' cpufreq governor"
+ depends on CPU_FREQ && NO_HZ && HOTPLUG_CPU
+ help
+ 'hotplug' - this driver mimics the frequency scaling behavior
+ in 'ondemand', but with several key differences. First is
+ that frequency transitions use the CPUFreq table directly,
+ instead of incrementing in a percentage of the maximum
+ available frequency. Second 'hotplug' will offline auxillary
+ CPUs when the system is idle, and online those CPUs once the
+ system becomes busy again. This last feature is needed for
+ architectures which transition to low power states when only
+ the "master" CPU is online, or for thermally constrained
+ devices.
+
+ If you don't have one of these architectures or devices, use
+ 'ondemand' instead.
+
+ If in doubt, say N.
+
endif # CPU_FREQ
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 71fc3b4..05d564c 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
+obj-$(CONFIG_CPU_FREQ_GOV_HOTPLUG) += cpufreq_hotplug.o
# CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
diff --git a/drivers/cpufreq/cpufreq_hotplug.c b/drivers/cpufreq/cpufreq_hotplug.c
new file mode 100644
index 0000000..85aa6d2
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_hotplug.c
@@ -0,0 +1,705 @@
+/*
+ * CPUFreq hotplug governor
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Mike Turquette <mturquette@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Based on ondemand governor
+ * Copyright (C) 2001 Russell King
+ * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>,
+ * Jun Nakajima <jun.nakajima@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu.h>
+#include <linux/jiffies.h>
+#include <linux/kernel_stat.h>
+#include <linux/mutex.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+#include <linux/ktime.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+/* greater than 80% avg load across online CPUs increases frequency */
+#define DEFAULT_UP_FREQ_MIN_LOAD (80)
+
+/* less than 20% avg load across online CPUs decreases frequency */
+#define DEFAULT_DOWN_FREQ_MAX_LOAD (20)
+
+/* default sampling period (uSec) is bogus; 10x ondemand's default for x86 */
+#define DEFAULT_SAMPLING_PERIOD (100000)
+
+/* default number of sampling periods to average before hotplug-in decision */
+#define DEFAULT_HOTPLUG_IN_SAMPLING_PERIODS (5)
+
+/* default number of sampling periods to average before hotplug-out decision */
+#define DEFAULT_HOTPLUG_OUT_SAMPLING_PERIODS (20)
+
+static void do_dbs_timer(struct work_struct *work);
+static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+ unsigned int event);
+
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG
+static
+#endif
+struct cpufreq_governor cpufreq_gov_hotplug = {
+ .name = "hotplug",
+ .governor = cpufreq_governor_dbs,
+ .owner = THIS_MODULE,
+};
+
+struct cpu_dbs_info_s {
+ cputime64_t prev_cpu_idle;
+ cputime64_t prev_cpu_wall;
+ cputime64_t prev_cpu_nice;
+ struct cpufreq_policy *cur_policy;
+ struct delayed_work work;
+ struct cpufreq_frequency_table *freq_table;
+ int cpu;
+ /*
+ * percpu mutex that serializes governor limit change with
+ * do_dbs_timer invocation. We do not want do_dbs_timer to run
+ * when user is changing the governor or limits.
+ */
+ struct mutex timer_mutex;
+};
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, hp_cpu_dbs_info);
+
+static unsigned int dbs_enable; /* number of CPUs using this policy */
+
+/*
+ * dbs_mutex protects data in dbs_tuners_ins from concurrent changes on
+ * different CPUs. It protects dbs_enable in governor start/stop.
+ */
+static DEFINE_MUTEX(dbs_mutex);
+
+static struct workqueue_struct *khotplug_wq;
+
+static struct dbs_tuners {
+ unsigned int sampling_rate;
+ unsigned int up_threshold;
+ unsigned int down_threshold;
+ unsigned int hotplug_in_sampling_periods;
+ unsigned int hotplug_out_sampling_periods;
+ unsigned int hotplug_load_index;
+ unsigned int *hotplug_load_history;
+ unsigned int ignore_nice;
+ unsigned int io_is_busy;
+} dbs_tuners_ins = {
+ .sampling_rate = DEFAULT_SAMPLING_PERIOD,
+ .up_threshold = DEFAULT_UP_FREQ_MIN_LOAD,
+ .down_threshold = DEFAULT_DOWN_FREQ_MAX_LOAD,
+ .hotplug_in_sampling_periods = DEFAULT_HOTPLUG_IN_SAMPLING_PERIODS,
+ .hotplug_out_sampling_periods = DEFAULT_HOTPLUG_OUT_SAMPLING_PERIODS,
+ .hotplug_load_index = 0,
+ .ignore_nice = 0,
+ .io_is_busy = 0,
+};
+
+/*
+ * A corner case exists when switching io_is_busy at run-time: comparing idle
+ * times from a non-io_is_busy period to an io_is_busy period (or vice-versa)
+ * will misrepresent the actual change in system idleness. We ignore this
+ * corner case: enabling io_is_busy might cause freq increase and disabling
+ * might cause freq decrease, which probably matches the original intent.
+ */
+static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
+{
+ u64 idle_time;
+ u64 iowait_time;
+
+ /* cpufreq-hotplug always assumes CONFIG_NO_HZ */
+ idle_time = get_cpu_idle_time_us(cpu, wall);
+
+ /* add time spent doing I/O to idle time */
+ if (dbs_tuners_ins.io_is_busy) {
+ iowait_time = get_cpu_iowait_time_us(cpu, wall);
+ /* cpufreq-hotplug always assumes CONFIG_NO_HZ */
+ if (iowait_time != -1ULL && idle_time >= iowait_time)
+ idle_time -= iowait_time;
+ }
+
+ return idle_time;
+}
+
+/************************** sysfs interface ************************/
+
+/* XXX look at global sysfs macros in cpufreq.h, can those be used here? */
+
+/* cpufreq_hotplug Governor Tunables */
+#define show_one(file_name, object) \
+static ssize_t show_##file_name \
+(struct kobject *kobj, struct attribute *attr, char *buf) \
+{ \
+ return sprintf(buf, "%u\n", dbs_tuners_ins.object); \
+}
+show_one(sampling_rate, sampling_rate);
+show_one(up_threshold, up_threshold);
+show_one(down_threshold, down_threshold);
+show_one(hotplug_in_sampling_periods, hotplug_in_sampling_periods);
+show_one(hotplug_out_sampling_periods, hotplug_out_sampling_periods);
+show_one(ignore_nice_load, ignore_nice);
+show_one(io_is_busy, io_is_busy);
+
+static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ mutex_lock(&dbs_mutex);
+ dbs_tuners_ins.sampling_rate = input;
+ mutex_unlock(&dbs_mutex);
+
+ return count;
+}
+
+static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+
+ if (ret != 1 || input <= dbs_tuners_ins.down_threshold) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&dbs_mutex);
+ dbs_tuners_ins.up_threshold = input;
+ mutex_unlock(&dbs_mutex);
+
+ return count;
+}
+
+static ssize_t store_down_threshold(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+
+ if (ret != 1 || input >= dbs_tuners_ins.up_threshold) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&dbs_mutex);
+ dbs_tuners_ins.down_threshold = input;
+ mutex_unlock(&dbs_mutex);
+
+ return count;
+}
+
+static ssize_t store_hotplug_in_sampling_periods(struct kobject *a,
+ struct attribute *b, const char *buf, size_t count)
+{
+ unsigned int input;
+ unsigned int *temp;
+ unsigned int max_windows;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+
+ if (ret != 1)
+ return -EINVAL;
+
+ /* already using this value, bail out */
+ if (input == dbs_tuners_ins.hotplug_in_sampling_periods)
+ return count;
+
+ mutex_lock(&dbs_mutex);
+ ret = count;
+ max_windows = max(dbs_tuners_ins.hotplug_in_sampling_periods,
+ dbs_tuners_ins.hotplug_out_sampling_periods);
+
+ /* no need to resize array */
+ if (input <= max_windows) {
+ dbs_tuners_ins.hotplug_in_sampling_periods = input;
+ goto out;
+ }
+
+ /* resize array */
+ temp = kmalloc((sizeof(unsigned int) * input), GFP_KERNEL);
+
+ if (!temp || IS_ERR(temp)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(temp, dbs_tuners_ins.hotplug_load_history,
+ (max_windows * sizeof(unsigned int)));
+ kfree(dbs_tuners_ins.hotplug_load_history);
+
+ /* replace old buffer, old number of sampling periods & old index */
+ dbs_tuners_ins.hotplug_load_history = temp;
+ dbs_tuners_ins.hotplug_in_sampling_periods = input;
+ dbs_tuners_ins.hotplug_load_index = max_windows;
+out:
+ mutex_unlock(&dbs_mutex);
+
+ return ret;
+}
+
+static ssize_t store_hotplug_out_sampling_periods(struct kobject *a,
+ struct attribute *b, const char *buf, size_t count)
+{
+ unsigned int input;
+ unsigned int *temp;
+ unsigned int max_windows;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+
+ if (ret != 1)
+ return -EINVAL;
+
+ /* already using this value, bail out */
+ if (input == dbs_tuners_ins.hotplug_out_sampling_periods)
+ return count;
+
+ mutex_lock(&dbs_mutex);
+ ret = count;
+ max_windows = max(dbs_tuners_ins.hotplug_in_sampling_periods,
+ dbs_tuners_ins.hotplug_out_sampling_periods);
+
+ /* no need to resize array */
+ if (input <= max_windows) {
+ dbs_tuners_ins.hotplug_out_sampling_periods = input;
+ goto out;
+ }
+
+ /* resize array */
+ temp = kmalloc((sizeof(unsigned int) * input), GFP_KERNEL);
+
+ if (!temp || IS_ERR(temp)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(temp, dbs_tuners_ins.hotplug_load_history,
+ (max_windows * sizeof(unsigned int)));
+ kfree(dbs_tuners_ins.hotplug_load_history);
+
+ /* replace old buffer, old number of sampling periods & old index */
+ dbs_tuners_ins.hotplug_load_history = temp;
+ dbs_tuners_ins.hotplug_out_sampling_periods = input;
+ dbs_tuners_ins.hotplug_load_index = max_windows;
+out:
+ mutex_unlock(&dbs_mutex);
+
+ return ret;
+}
+
+static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+
+ unsigned int j;
+
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ if (input > 1)
+ input = 1;
+
+ mutex_lock(&dbs_mutex);
+ if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */
+ mutex_unlock(&dbs_mutex);
+ return count;
+ }
+ dbs_tuners_ins.ignore_nice = input;
+
+ /* we need to re-evaluate prev_cpu_idle */
+ for_each_online_cpu(j) {
+ struct cpu_dbs_info_s *dbs_info;
+ dbs_info = &per_cpu(hp_cpu_dbs_info, j);
+ dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
+ &dbs_info->prev_cpu_wall);
+ if (dbs_tuners_ins.ignore_nice)
+ dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
+
+ }
+ mutex_unlock(&dbs_mutex);
+
+ return count;
+}
+
+static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ mutex_lock(&dbs_mutex);
+ dbs_tuners_ins.io_is_busy = !!input;
+ mutex_unlock(&dbs_mutex);
+
+ return count;
+}
+
+define_one_global_rw(sampling_rate);
+define_one_global_rw(up_threshold);
+define_one_global_rw(down_threshold);
+define_one_global_rw(hotplug_in_sampling_periods);
+define_one_global_rw(hotplug_out_sampling_periods);
+define_one_global_rw(ignore_nice_load);
+define_one_global_rw(io_is_busy);
+
+static struct attribute *dbs_attributes[] = {
+ &sampling_rate.attr,
+ &up_threshold.attr,
+ &down_threshold.attr,
+ &hotplug_in_sampling_periods.attr,
+ &hotplug_out_sampling_periods.attr,
+ &ignore_nice_load.attr,
+ &io_is_busy.attr,
+ NULL
+};
+
+static struct attribute_group dbs_attr_group = {
+ .attrs = dbs_attributes,
+ .name = "hotplug",
+};
+
+/************************** sysfs end ************************/
+
+static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
+{
+ /* combined load of all enabled CPUs */
+ unsigned int total_load = 0;
+ /* single largest CPU load */
+ unsigned int max_load = 0;
+ /* average load across all enabled CPUs */
+ unsigned int avg_load = 0;
+ /* average load across multiple sampling periods for hotplug events */
+ unsigned int hotplug_in_avg_load = 0;
+ unsigned int hotplug_out_avg_load = 0;
+ /* number of sampling periods averaged for hotplug decisions */
+ unsigned int periods;
+
+ struct cpufreq_policy *policy;
+ unsigned int index = 0;
+ unsigned int i, j;
+
+ policy = this_dbs_info->cur_policy;
+
+ /*
+ * cpu load accounting
+ * get highest load, total load and average load across all CPUs
+ */
+ for_each_cpu(j, policy->cpus) {
+ unsigned int load;
+ unsigned int idle_time, wall_time;
+ cputime64_t cur_wall_time, cur_idle_time;
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(hp_cpu_dbs_info, j);
+
+ /* update both cur_idle_time and cur_wall_time */
+ cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
+
+ /* how much wall time has passed since last iteration? */
+ wall_time = (unsigned int) cputime64_sub(cur_wall_time,
+ j_dbs_info->prev_cpu_wall);
+ j_dbs_info->prev_cpu_wall = cur_wall_time;
+
+ /* how much idle time has passed since last iteration? */
+ idle_time = (unsigned int) cputime64_sub(cur_idle_time,
+ j_dbs_info->prev_cpu_idle);
+ j_dbs_info->prev_cpu_idle = cur_idle_time;
+
+ if (unlikely(!wall_time || wall_time < idle_time))
+ continue;
+
+ /* load is the percentage of time not spent in idle */
+ load = 100 * (wall_time - idle_time) / wall_time;
+
+ /* keep track of combined load across all CPUs */
+ total_load += load;
+
+ /* keep track of highest single load across all CPUs */
+ if (load > max_load)
+ max_load = load;
+ }
+
+ /* calculate the average load across all related CPUs */
+ avg_load = total_load / num_online_cpus();
+
+
+ /*
+ * hotplug load accounting
+ * average load over multiple sampling periods
+ */
+
+ /* how many sampling periods do we use for hotplug decisions? */
+ periods = max(dbs_tuners_ins.hotplug_in_sampling_periods,
+ dbs_tuners_ins.hotplug_out_sampling_periods);
+
+ /* store avg_load in the circular buffer */
+ dbs_tuners_ins.hotplug_load_history[dbs_tuners_ins.hotplug_load_index]
+ = avg_load;
+
+ /* compute average load across in & out sampling periods */
+ for (i = 0, j = dbs_tuners_ins.hotplug_load_index;
+ i < periods; i++, j--) {
+ if (i < dbs_tuners_ins.hotplug_in_sampling_periods)
+ hotplug_in_avg_load +=
+ dbs_tuners_ins.hotplug_load_history[j];
+ if (i < dbs_tuners_ins.hotplug_out_sampling_periods)
+ hotplug_out_avg_load +=
+ dbs_tuners_ins.hotplug_load_history[j];
+
+ if (j == 0)
+ j = periods;
+ }
+
+ hotplug_in_avg_load = hotplug_in_avg_load /
+ dbs_tuners_ins.hotplug_in_sampling_periods;
+
+ hotplug_out_avg_load = hotplug_out_avg_load /
+ dbs_tuners_ins.hotplug_out_sampling_periods;
+
+ /* return to first element if we're at the circular buffer's end */
+ if (++dbs_tuners_ins.hotplug_load_index == periods)
+ dbs_tuners_ins.hotplug_load_index = 0;
+
+ /* check for frequency increase */
+ if (avg_load > dbs_tuners_ins.up_threshold) {
+ /* should we enable auxillary CPUs? */
+ if (num_online_cpus() < 2 && hotplug_in_avg_load >
+ dbs_tuners_ins.up_threshold) {
+ /* hotplug with cpufreq is nasty
+ * a call to cpufreq_governor_dbs may cause a lockup.
+ * wq is not running here so its safe.
+ */
+ mutex_unlock(&this_dbs_info->timer_mutex);
+ cpu_up(1);
+ mutex_lock(&this_dbs_info->timer_mutex);
+ goto out;
+ }
+
+ /* increase to highest frequency supported */
+ if (policy->cur < policy->max)
+ __cpufreq_driver_target(policy, policy->max,
+ CPUFREQ_RELATION_H);
+
+ goto out;
+ }
+
+ /* check for frequency decrease */
+ if (avg_load < dbs_tuners_ins.down_threshold) {
+ /* are we at the minimum frequency already? */
+ if (policy->cur == policy->min) {
+ /* should we disable auxillary CPUs? */
+ if (num_online_cpus() > 1 && hotplug_out_avg_load <
+ dbs_tuners_ins.down_threshold) {
+ mutex_unlock(&this_dbs_info->timer_mutex);
+ cpu_down(1);
+ mutex_lock(&this_dbs_info->timer_mutex);
+ }
+ goto out;
+ }
+
+ /* bump down to the next lowest frequency in the table */
+ if (cpufreq_frequency_table_next_lowest(policy,
+ this_dbs_info->freq_table, &index)) {
+ pr_err("%s: failed to get next lowest frequency\n",
+ __func__);
+ goto out;
+ }
+
+ __cpufreq_driver_target(policy,
+ this_dbs_info->freq_table[index].frequency,
+ CPUFREQ_RELATION_L);
+ }
+out:
+ return;
+}
+
+static void do_dbs_timer(struct work_struct *work)
+{
+ struct cpu_dbs_info_s *dbs_info =
+ container_of(work, struct cpu_dbs_info_s, work.work);
+ unsigned int cpu = dbs_info->cpu;
+
+ /* We want all related CPUs to do sampling nearly on same jiffy */
+ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+
+ mutex_lock(&dbs_info->timer_mutex);
+ dbs_check_cpu(dbs_info);
+ queue_delayed_work_on(cpu, khotplug_wq, &dbs_info->work, delay);
+ mutex_unlock(&dbs_info->timer_mutex);
+}
+
+static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
+{
+ /* We want all related CPUs to do sampling nearly on same jiffy */
+ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+ delay -= jiffies % delay;
+
+ INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
+ queue_delayed_work_on(dbs_info->cpu, khotplug_wq, &dbs_info->work,
+ delay);
+}
+
+static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
+{
+ cancel_delayed_work_sync(&dbs_info->work);
+}
+
+static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+ unsigned int event)
+{
+ unsigned int cpu = policy->cpu;
+ struct cpu_dbs_info_s *this_dbs_info;
+ unsigned int i, j, max_periods;
+ int rc;
+
+ this_dbs_info = &per_cpu(hp_cpu_dbs_info, cpu);
+
+ switch (event) {
+ case CPUFREQ_GOV_START:
+ if ((!cpu_online(cpu)) || (!policy->cur))
+ return -EINVAL;
+
+ mutex_lock(&dbs_mutex);
+ dbs_enable++;
+ for_each_cpu(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(hp_cpu_dbs_info, j);
+ j_dbs_info->cur_policy = policy;
+
+ j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
+ &j_dbs_info->prev_cpu_wall);
+ if (dbs_tuners_ins.ignore_nice) {
+ j_dbs_info->prev_cpu_nice =
+ kstat_cpu(j).cpustat.nice;
+ }
+
+ max_periods = max(DEFAULT_HOTPLUG_IN_SAMPLING_PERIODS,
+ DEFAULT_HOTPLUG_OUT_SAMPLING_PERIODS);
+ dbs_tuners_ins.hotplug_load_history = kmalloc(
+ (sizeof(unsigned int) * max_periods),
+ GFP_KERNEL);
+ if (!dbs_tuners_ins.hotplug_load_history) {
+ WARN_ON(1);
+ return -ENOMEM;
+ }
+ for (i = 0; i < max_periods; i++)
+ dbs_tuners_ins.hotplug_load_history[i] = 50;
+ }
+ this_dbs_info->cpu = cpu;
+ this_dbs_info->freq_table = cpufreq_frequency_get_table(cpu);
+ /*
+ * Start the timerschedule work, when this governor
+ * is used for first time
+ */
+ if (dbs_enable == 1) {
+ rc = sysfs_create_group(cpufreq_global_kobject,
+ &dbs_attr_group);
+ if (rc) {
+ mutex_unlock(&dbs_mutex);
+ return rc;
+ }
+ }
+ mutex_unlock(&dbs_mutex);
+
+ mutex_init(&this_dbs_info->timer_mutex);
+ dbs_timer_init(this_dbs_info);
+ break;
+
+ case CPUFREQ_GOV_STOP:
+ dbs_timer_exit(this_dbs_info);
+
+ mutex_lock(&dbs_mutex);
+ mutex_destroy(&this_dbs_info->timer_mutex);
+ dbs_enable--;
+ mutex_unlock(&dbs_mutex);
+ if (!dbs_enable)
+ sysfs_remove_group(cpufreq_global_kobject,
+ &dbs_attr_group);
+ kfree(dbs_tuners_ins.hotplug_load_history);
+ /*
+ * XXX BIG CAVEAT: Stopping the governor with CPU1 offline
+ * will result in it remaining offline until the user onlines
+ * it again. It is up to the user to do this (for now).
+ */
+ break;
+
+ case CPUFREQ_GOV_LIMITS:
+ mutex_lock(&this_dbs_info->timer_mutex);
+ if (policy->max < this_dbs_info->cur_policy->cur)
+ __cpufreq_driver_target(this_dbs_info->cur_policy,
+ policy->max, CPUFREQ_RELATION_H);
+ else if (policy->min > this_dbs_info->cur_policy->cur)
+ __cpufreq_driver_target(this_dbs_info->cur_policy,
+ policy->min, CPUFREQ_RELATION_L);
+ mutex_unlock(&this_dbs_info->timer_mutex);
+ break;
+ }
+ return 0;
+}
+
+static int __init cpufreq_gov_dbs_init(void)
+{
+ int err;
+ cputime64_t wall;
+ u64 idle_time;
+ int cpu = get_cpu();
+
+ idle_time = get_cpu_idle_time_us(cpu, &wall);
+ put_cpu();
+ if (idle_time != -1ULL) {
+ dbs_tuners_ins.up_threshold = DEFAULT_UP_FREQ_MIN_LOAD;
+ } else {
+ pr_err("cpufreq-hotplug: %s: assumes CONFIG_NO_HZ\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ khotplug_wq = create_workqueue("khotplug");
+ if (!khotplug_wq) {
+ pr_err("Creation of khotplug failed\n");
+ return -EFAULT;
+ }
+ err = cpufreq_register_governor(&cpufreq_gov_hotplug);
+ if (err)
+ destroy_workqueue(khotplug_wq);
+
+ return err;
+}
+
+static void __exit cpufreq_gov_dbs_exit(void)
+{
+ cpufreq_unregister_governor(&cpufreq_gov_hotplug);
+ destroy_workqueue(khotplug_wq);
+}
+
+MODULE_AUTHOR("Mike Turquette <mturquette@ti.com>");
+MODULE_DESCRIPTION("'cpufreq_hotplug' - cpufreq governor for dynamic frequency scaling and CPU hotplugging");
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG
+fs_initcall(cpufreq_gov_dbs_init);
+#else
+module_init(cpufreq_gov_dbs_init);
+#endif
+module_exit(cpufreq_gov_dbs_exit);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index a38fca8..6cbc3df 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -355,6 +355,9 @@ extern struct cpufreq_governor cpufreq_gov_ondemand;
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE)
extern struct cpufreq_governor cpufreq_gov_conservative;
#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative)
+#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG)
+extern struct cpufreq_governor cpufreq_gov_hotplug;
+#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_hotplug)
#endif
--
1.6.6.1
@@ -1,27 +0,0 @@
From 33668b07abd5e66a263cc8b4b88587646f38bed0 Mon Sep 17 00:00:00 2001
From: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com>
Date: Wed, 11 Aug 2010 17:02:43 -0700
Subject: [PATCH 1/8] OMAP: CPUfreq: ensure driver initializes after cpufreq framework and governors
Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
arch/arm/plat-omap/cpu-omap.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index da4f68d..cd09d4b 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -160,7 +160,7 @@ static int __init omap_cpufreq_init(void)
return cpufreq_register_driver(&omap_driver);
}
-arch_initcall(omap_cpufreq_init);
+late_initcall(omap_cpufreq_init);
/*
* if ever we want to remove this, upon cleanup call:
--
1.6.6.1
@@ -1,31 +0,0 @@
From e89b1544450fb8410a44004e48d6b330bc39f0ce Mon Sep 17 00:00:00 2001
From: Kevin Hilman <khilman@deeprootsystems.com>
Date: Wed, 11 Aug 2010 17:05:38 -0700
Subject: [PATCH 2/8] OMAP: CPUfreq: ensure policy is fully initialized
Ensure policy min/max/cur values are initialized when OMAP
CPUfreq driver starts.
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
arch/arm/plat-omap/cpu-omap.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index cd09d4b..1b36664 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -126,6 +126,10 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
VERY_HI_RATE) / 1000;
}
+ policy->min = policy->cpuinfo.min_freq;
+ policy->max = policy->cpuinfo.max_freq;
+ policy->cur = omap_getspeed(0);
+
/* FIXME: what's the actual transition time? */
policy->cpuinfo.transition_latency = 300 * 1000;
--
1.6.6.1
@@ -1,263 +0,0 @@
From 948b868e4a83b054e8a58362238bc6cd61c0aeab Mon Sep 17 00:00:00 2001
From: Rajendra Nayak <rnayak@ti.com>
Date: Mon, 10 Nov 2008 17:00:25 +0530
Subject: [PATCH 3/8] OMAP3 PM: CPUFreq driver for OMAP3
CPUFreq driver for OMAP3
With additional fixes and cleanups from Tero Kristo:
- Fix rate calculation bug in omap3_select_table_rate
- Refreshed DVFS VDD1 control against latest clock fw
Signed-off-by: Tero Kristo <tero.kristo@nokia.com>
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
OMAP3: PM: CPUFreq: Fix omap_getspeed.
Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com>
Make sure omap cpufreq driver initializes after cpufreq framework and governors
Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com>
merge: CPUFreq: remove obsolete funcs
OMAP3 clock: Update cpufreq driver
This patch removes all refrences to virtual clock
nodes in CPUFreq driver.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Tero Kristo <tero.kristo@nokia.com>
Signed-off-by: Jean Pihet <jpihet@mvista.com>
PM: Prevent direct cpufreq scaling during initialization
It is seen that the OMAP specific cpufreq initialization code tries to
scale the MPU frequency to the highest possible without taking care of
the voltage level. On power on reset the power IC does not provide the
necessary voltage for the highest available MPU frequency (that would
satisfy all Si families). This potentially is an window of opportunity
for things to go wrong.
Signed-off-by: Romit Dasgupta <romit@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
OMAP3: PM: enable 600MHz (overdrive) OPP
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
omap3: introduce cpufreq
OMAP OPP layer functions now have dependencies of CONFIG_CPU_FREQ only.
With this patch, omap opp layer now has its compilation flags
bound to CONFIG_CPU_FREQ. Also its code has been removed from pm34xx.c.
A new file has been created to contain cpu freq code related to
OMAP3: cpufreq34xx.c
OMAP34xx and OMAP36xx family OPPs are made available
Signed-off-by: Eduardo Valentin <eduardo.valentin@nokia.com>
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Vishwanath BS <vishwanath.bs@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Signed-off-by: Romit Dasgupta <romit@ti.com>
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
omap3: cpufreq: allow default opp table init
For board files which choose to override the defaults, the existing
mechanism will work, for boards that would like to work with defaults,
allow init_common_hw to call init_opp_table to initialize if not
already initialized. this will allow all omap boards which have opp
tables predefined for a silicon to use the same.
Originally reported for overo:
http://marc.info/?t=127265269400004&r=1&w=2
Signed-off-by: Nishanth Menon <nm@ti.com>
Reported-by: Peter Tseng <tsenpet09@gmail.com>
Cc: Cliff Brake <cliff.brake@gmail.com>
Cc: Kevin Hilman <khilman@deeprootsystems.com>
OMAP2: update OPP data to be device based
Cc: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
OMAP3: CPUfreq: update to device-based OPP API
Update usage of OPP API to use new device-based API. This requires
getting the 'struct device' for the MPU and using that with the OPP
API.
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
omap3: opp: make independent of cpufreq
Make opp3xx data which is registered with the opp layer
dependent purely on CONFIG_PM as opp layer and pm.c users
are CONFIG_PM dependent not cpufreq dependent.
so we rename the data definition to opp3xxx_data.c (inline with what
we have for omap2), also move the build definition to be under
the existing CONFIG_PM build instead of CPUFREQ.
Cc: Eduardo Valentin <eduardo.valentin@nokia.com>
Cc: Kevin Hilman <khilman@deeprootsystems.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Rajendra Nayak <rnayak@ti.com>
Cc: Sanjeev Premi <premi@ti.com>
Cc: Thara Gopinath <thara@ti.com>
Cc: Tony Lindgren <tony@atomide.com>
Signed-off-by: Nishanth Menon <nm@ti.com>
---
arch/arm/mach-omap2/clock.h | 14 +++++++++++++-
arch/arm/mach-omap2/clock34xx.c | 2 ++
arch/arm/plat-omap/cpu-omap.c | 34 +++++++++++++++++++++++++++++++---
3 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index e10ff2b..0a07e50 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -141,7 +141,9 @@ extern const struct clksel_rate gpt_sys_rates[];
extern const struct clksel_rate gfx_l3_rates[];
extern const struct clksel_rate dsp_ick_rates[];
-#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_CPU_FREQ)
+#ifdef CONFIG_CPU_FREQ
+
+#ifdef CONFIG_ARCH_OMAP2
extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table);
#else
@@ -149,6 +151,16 @@ extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
#define omap2_clk_exit_cpufreq_table 0
#endif
+#ifdef CONFIG_ARCH_OMAP3
+extern void omap3_clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
+extern void omap3_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table);
+#else
+#define omap3_clk_init_cpufreq_table 0
+#define omap3_clk_exit_cpufreq_table 0
+#endif
+
+#endif /* CONFIG_CPU_FREQ */
+
extern const struct clkops clkops_omap2_iclk_dflt_wait;
extern const struct clkops clkops_omap2_iclk_dflt;
extern const struct clkops clkops_omap2_iclk_idle_only;
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index 1fc96b9..119e135 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -20,6 +20,8 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/cpufreq.h>
#include <plat/clock.h>
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index 1b36664..f0f9430 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -8,6 +8,10 @@
*
* Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
*
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Updated to support OMAP3
+ * Rajendra Nayak <rnayak@ti.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -26,12 +30,19 @@
#include <plat/clock.h>
#include <asm/system.h>
+#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
+#include <plat/omap-pm.h>
+#include <plat/opp.h>
+#endif
+
#define VERY_HI_RATE 900000000
static struct cpufreq_frequency_table *freq_table;
#ifdef CONFIG_ARCH_OMAP1
#define MPU_CLK "mpu"
+#elif CONFIG_ARCH_OMAP3
+#define MPU_CLK "arm_fck"
#else
#define MPU_CLK "virt_prcm_set"
#endif
@@ -73,7 +84,13 @@ static int omap_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
+#ifdef CONFIG_ARCH_OMAP1
struct cpufreq_freqs freqs;
+#endif
+#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
+ unsigned long freq;
+ struct device *mpu_dev = omap2_get_mpuss_device();
+#endif
int ret = 0;
/* Ensure desired rate is within allowed range. Some govenors
@@ -83,13 +100,13 @@ static int omap_target(struct cpufreq_policy *policy,
if (target_freq > policy->max)
target_freq = policy->max;
+#ifdef CONFIG_ARCH_OMAP1
freqs.old = omap_getspeed(0);
freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
freqs.cpu = 0;
if (freqs.old == freqs.new)
return ret;
-
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
#ifdef CONFIG_CPU_FREQ_DEBUG
printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n",
@@ -97,7 +114,11 @@ static int omap_target(struct cpufreq_policy *policy,
#endif
ret = clk_set_rate(mpu_clk, freqs.new * 1000);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
+#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
+ freq = target_freq * 1000;
+ if (opp_find_freq_ceil(mpu_dev, &freq))
+ omap_pm_cpu_set_freq(freq);
+#endif
return ret;
}
@@ -114,7 +135,14 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
policy->cur = policy->min = policy->max = omap_getspeed(0);
- clk_init_cpufreq_table(&freq_table);
+ if (!cpu_is_omap34xx()) {
+ clk_init_cpufreq_table(&freq_table);
+ } else {
+ struct device *mpu_dev = omap2_get_mpuss_device();
+
+ opp_init_cpufreq_table(mpu_dev, &freq_table);
+ }
+
if (freq_table) {
result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
if (!result)
--
1.6.6.1
@@ -1,32 +0,0 @@
From 86227f1eb341e571163464cb0a412ed2179f2541 Mon Sep 17 00:00:00 2001
From: Silesh C V <silesh@ti.com>
Date: Wed, 29 Sep 2010 14:52:54 +0530
Subject: [PATCH 4/8] OMAP: PM: CPUFREQ: Fix conditional compilation
Fix conditional compilation. A conditional expresiion
should follow "#elif", in this case #elif clause should
check whether CONFIG_ARCH_OMAP3 is defined or not
(ie. defined(CONFIG_ARCH_OMAP3)) rather than checking for
the value of the macro.
Signed-off-by: Silesh C V <silesh@ti.com>
---
arch/arm/plat-omap/cpu-omap.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index f0f9430..c3ac065 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -41,7 +41,7 @@ static struct cpufreq_frequency_table *freq_table;
#ifdef CONFIG_ARCH_OMAP1
#define MPU_CLK "mpu"
-#elif CONFIG_ARCH_OMAP3
+#elif defined(CONFIG_ARCH_OMAP3)
#define MPU_CLK "arm_fck"
#else
#define MPU_CLK "virt_prcm_set"
--
1.6.6.1
@@ -1,33 +0,0 @@
From 4764137dd613362656726a15cb8184724aeb99bb Mon Sep 17 00:00:00 2001
From: Kevin Hilman <khilman@deeprootsystems.com>
Date: Tue, 16 Nov 2010 11:48:41 -0800
Subject: [PATCH 5/8] cpufreq: fixup after new OPP layer merged
---
arch/arm/plat-omap/cpu-omap.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index c3ac065..9cd2709 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -25,6 +25,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/opp.h>
#include <mach/hardware.h>
#include <plat/clock.h>
@@ -32,7 +33,7 @@
#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
#include <plat/omap-pm.h>
-#include <plat/opp.h>
+#include <plat/common.h>
#endif
#define VERY_HI_RATE 900000000
--
1.6.6.1
@@ -1,669 +0,0 @@
From e16548716c5cbc3c9885d05f1654d83d5411a3a7 Mon Sep 17 00:00:00 2001
From: Santosh Shilimkar <santosh.shilimkar@ti.com>
Date: Mon, 14 Mar 2011 17:08:48 +0530
Subject: [PATCH 6/8] OMAP: cpufreq: Split OMAP1 and OMAP2PLUS CPUfreq drivers.
This patch is an attempt to cleanup the #ifdeferry in the
omap CPUfreq drivers.
The split betwenn OMAP1 and OMAP2PLUS is logical because
- OMAP1 doesn't support opp layer.
- OMAP1 build is seperate from omap2plus.
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Vishwanath BS <vishwanath.bs@ti.com>
---
arch/arm/mach-omap1/Makefile | 3 +
arch/arm/mach-omap1/omap1-cpufreq.c | 176 ++++++++++++++++++++++++++
arch/arm/mach-omap2/Makefile | 3 +
arch/arm/mach-omap2/omap2plus-cpufreq.c | 201 ++++++++++++++++++++++++++++++
arch/arm/plat-omap/Makefile | 1 -
arch/arm/plat-omap/cpu-omap.c | 204 -------------------------------
6 files changed, 383 insertions(+), 205 deletions(-)
create mode 100644 arch/arm/mach-omap1/omap1-cpufreq.c
create mode 100644 arch/arm/mach-omap2/omap2plus-cpufreq.c
delete mode 100644 arch/arm/plat-omap/cpu-omap.c
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index af98117..e5082b0 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -10,6 +10,9 @@ obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
+# CPUFREQ driver
+obj-$(CONFIG_CPU_FREQ) += omap1-cpufreq.o
+
# Power Management
obj-$(CONFIG_PM) += pm.o sleep.o pm_bus.o
diff --git a/arch/arm/mach-omap1/omap1-cpufreq.c b/arch/arm/mach-omap1/omap1-cpufreq.c
new file mode 100644
index 0000000..682cdc8
--- /dev/null
+++ b/arch/arm/mach-omap1/omap1-cpufreq.c
@@ -0,0 +1,176 @@
+/*
+ * OMAP1 cpufreq driver
+ *
+ * CPU frequency scaling for OMAP
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Updated to support OMAP3
+ * Rajendra Nayak <rnayak@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/opp.h>
+
+#include <asm/system.h>
+
+#include <plat/clock.h>
+#include <plat/omap-pm.h>
+
+#include <mach/hardware.h>
+
+#define VERY_HI_RATE 900000000
+
+static struct cpufreq_frequency_table *freq_table;
+static struct clk *mpu_clk;
+
+static int omap_verify_speed(struct cpufreq_policy *policy)
+{
+ if (freq_table)
+ return cpufreq_frequency_table_verify(policy, freq_table);
+
+ if (policy->cpu)
+ return -EINVAL;
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+
+ policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000;
+ policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000;
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ return 0;
+}
+
+static unsigned int omap_getspeed(unsigned int cpu)
+{
+ unsigned long rate;
+
+ if (cpu)
+ return 0;
+
+ rate = clk_get_rate(mpu_clk) / 1000;
+ return rate;
+}
+
+static int omap_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ int ret = 0;
+
+ /* Ensure desired rate is within allowed range. Some govenors
+ * (ondemand) will just pass target_freq=0 to get the minimum. */
+ if (target_freq < policy->min)
+ target_freq = policy->min;
+ if (target_freq > policy->max)
+ target_freq = policy->max;
+
+ freqs.old = omap_getspeed(0);
+ freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
+ freqs.cpu = 0;
+
+ if (freqs.old == freqs.new)
+ return ret;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+ pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
+#endif
+ ret = clk_set_rate(mpu_clk, freqs.new * 1000);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return ret;
+}
+
+static int __init omap_cpu_init(struct cpufreq_policy *policy)
+{
+ int result = 0;
+
+ mpu_clk = clk_get(NULL, "mpu");
+ if (IS_ERR(mpu_clk))
+ return PTR_ERR(mpu_clk);
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = policy->min = policy->max = omap_getspeed(0);
+
+ clk_init_cpufreq_table(&freq_table);
+
+ if (freq_table) {
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (!result)
+ cpufreq_frequency_table_get_attr(freq_table,
+ policy->cpu);
+ } else {
+ policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
+ policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
+ VERY_HI_RATE) / 1000;
+ }
+
+ policy->min = policy->cpuinfo.min_freq;
+ policy->max = policy->cpuinfo.max_freq;
+ policy->cur = omap_getspeed(0);
+
+ /* FIXME: what's the actual transition time? */
+ policy->cpuinfo.transition_latency = 300 * 1000;
+
+ return 0;
+}
+
+static int omap_cpu_exit(struct cpufreq_policy *policy)
+{
+ clk_exit_cpufreq_table(&freq_table);
+ clk_put(mpu_clk);
+ return 0;
+}
+
+static struct freq_attr *omap_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver omap_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = omap_verify_speed,
+ .target = omap_target,
+ .get = omap_getspeed,
+ .init = omap_cpu_init,
+ .exit = omap_cpu_exit,
+ .name = "omap1",
+ .attr = omap_cpufreq_attr,
+};
+
+static int __init omap_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&omap_driver);
+}
+
+static void __exit omap_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&omap_driver);
+}
+
+MODULE_DESCRIPTION("cpufreq driver for OMAP1 SOCs");
+MODULE_LICENSE("GPL");
+module_init(omap_cpufreq_init);
+module_exit(omap_cpufreq_exit);
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 05cd983..e9c2445 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -56,6 +56,9 @@ obj-$(CONFIG_ARCH_OMAP3) += opp3xxx_data.o
obj-$(CONFIG_ARCH_OMAP4) += opp4xxx_data.o
endif
+# CPUFREQ driver
+obj-$(CONFIG_CPU_FREQ) += omap2plus-cpufreq.o
+
# Power Management
ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
new file mode 100644
index 0000000..14f84cc
--- /dev/null
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -0,0 +1,201 @@
+/*
+ * OMAP2PLUS cpufreq driver
+ *
+ * CPU frequency scaling for OMAP
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Updated to support OMAP3
+ * Rajendra Nayak <rnayak@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/opp.h>
+
+#include <asm/system.h>
+#include <asm/smp_plat.h>
+
+#include <plat/clock.h>
+#include <plat/omap-pm.h>
+#include <plat/common.h>
+
+#include <mach/hardware.h>
+
+#define VERY_HI_RATE 900000000
+
+static struct cpufreq_frequency_table *freq_table;
+static struct clk *mpu_clk;
+
+static int omap_verify_speed(struct cpufreq_policy *policy)
+{
+ if (freq_table)
+ return cpufreq_frequency_table_verify(policy, freq_table);
+
+ if (policy->cpu)
+ return -EINVAL;
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+
+ policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000;
+ policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000;
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ return 0;
+}
+
+static unsigned int omap_getspeed(unsigned int cpu)
+{
+ unsigned long rate;
+
+ if (cpu)
+ return 0;
+
+ rate = clk_get_rate(mpu_clk) / 1000;
+ return rate;
+}
+
+static int omap_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ int ret = 0;
+ struct cpufreq_freqs freqs;
+
+ /* Ensure desired rate is within allowed range. Some govenors
+ * (ondemand) will just pass target_freq=0 to get the minimum. */
+ if (target_freq < policy->min)
+ target_freq = policy->min;
+ if (target_freq > policy->max)
+ target_freq = policy->max;
+
+ freqs.old = omap_getspeed(0);
+ freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
+ freqs.cpu = 0;
+
+ if (freqs.old == freqs.new)
+ return ret;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+ pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
+#endif
+
+ ret = clk_set_rate(mpu_clk, freqs.new * 1000);
+
+ /*
+ * Generic CPUFREQ driver jiffy update is under !SMP. So jiffies
+ * won't get updated when UP machine cpufreq build with
+ * CONFIG_SMP enabled. Below code is added only to manage that
+ * scenario
+ */
+ if (!is_smp())
+ loops_per_jiffy =
+ cpufreq_scale(loops_per_jiffy, freqs.old, freqs.new);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return ret;
+}
+
+static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
+{
+ int result = 0;
+ struct device *mpu_dev;
+
+ if (cpu_is_omap24xx())
+ mpu_clk = clk_get(NULL, "virt_prcm_set");
+ else if (cpu_is_omap34xx())
+ mpu_clk = clk_get(NULL, "dpll1_ck");
+ else if (cpu_is_omap34xx())
+ mpu_clk = clk_get(NULL, "dpll_mpu_ck");
+
+ if (IS_ERR(mpu_clk))
+ return PTR_ERR(mpu_clk);
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->cur = policy->min = policy->max = omap_getspeed(0);
+
+ mpu_dev = omap2_get_mpuss_device();
+ if (!mpu_dev) {
+ pr_warning("%s: unable to get the mpu device\n", __func__);
+ return -EINVAL;
+ }
+ opp_init_cpufreq_table(mpu_dev, &freq_table);
+
+ if (freq_table) {
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (!result)
+ cpufreq_frequency_table_get_attr(freq_table,
+ policy->cpu);
+ } else {
+ policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
+ policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
+ VERY_HI_RATE) / 1000;
+ }
+
+ policy->min = policy->cpuinfo.min_freq;
+ policy->max = policy->cpuinfo.max_freq;
+ policy->cur = omap_getspeed(0);
+
+ /* FIXME: what's the actual transition time? */
+ policy->cpuinfo.transition_latency = 300 * 1000;
+
+ return 0;
+}
+
+static int omap_cpu_exit(struct cpufreq_policy *policy)
+{
+ clk_exit_cpufreq_table(&freq_table);
+ clk_put(mpu_clk);
+ return 0;
+}
+
+static struct freq_attr *omap_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver omap_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = omap_verify_speed,
+ .target = omap_target,
+ .get = omap_getspeed,
+ .init = omap_cpu_init,
+ .exit = omap_cpu_exit,
+ .name = "omap2plus",
+ .attr = omap_cpufreq_attr,
+};
+
+static int __init omap_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&omap_driver);
+}
+
+static void __exit omap_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&omap_driver);
+}
+
+MODULE_DESCRIPTION("cpufreq driver for OMAP2PLUS SOCs");
+MODULE_LICENSE("GPL");
+module_init(omap_cpufreq_init);
+module_exit(omap_cpufreq_exit);
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index a4a1285..ec7862e 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
obj-$(CONFIG_OMAP_IOMMU) += iommu.o iovmm.o
obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu-debug.o
-obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o
obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
deleted file mode 100644
index 9cd2709..0000000
--- a/arch/arm/plat-omap/cpu-omap.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * linux/arch/arm/plat-omap/cpu-omap.c
- *
- * CPU frequency scaling for OMAP
- *
- * Copyright (C) 2005 Nokia Corporation
- * Written by Tony Lindgren <tony@atomide.com>
- *
- * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
- *
- * Copyright (C) 2007-2008 Texas Instruments, Inc.
- * Updated to support OMAP3
- * Rajendra Nayak <rnayak@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/cpufreq.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/opp.h>
-
-#include <mach/hardware.h>
-#include <plat/clock.h>
-#include <asm/system.h>
-
-#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
-#include <plat/omap-pm.h>
-#include <plat/common.h>
-#endif
-
-#define VERY_HI_RATE 900000000
-
-static struct cpufreq_frequency_table *freq_table;
-
-#ifdef CONFIG_ARCH_OMAP1
-#define MPU_CLK "mpu"
-#elif defined(CONFIG_ARCH_OMAP3)
-#define MPU_CLK "arm_fck"
-#else
-#define MPU_CLK "virt_prcm_set"
-#endif
-
-static struct clk *mpu_clk;
-
-/* TODO: Add support for SDRAM timing changes */
-
-static int omap_verify_speed(struct cpufreq_policy *policy)
-{
- if (freq_table)
- return cpufreq_frequency_table_verify(policy, freq_table);
-
- if (policy->cpu)
- return -EINVAL;
-
- cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
- policy->cpuinfo.max_freq);
-
- policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000;
- policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000;
- cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
- policy->cpuinfo.max_freq);
- return 0;
-}
-
-static unsigned int omap_getspeed(unsigned int cpu)
-{
- unsigned long rate;
-
- if (cpu)
- return 0;
-
- rate = clk_get_rate(mpu_clk) / 1000;
- return rate;
-}
-
-static int omap_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
-{
-#ifdef CONFIG_ARCH_OMAP1
- struct cpufreq_freqs freqs;
-#endif
-#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
- unsigned long freq;
- struct device *mpu_dev = omap2_get_mpuss_device();
-#endif
- int ret = 0;
-
- /* Ensure desired rate is within allowed range. Some govenors
- * (ondemand) will just pass target_freq=0 to get the minimum. */
- if (target_freq < policy->min)
- target_freq = policy->min;
- if (target_freq > policy->max)
- target_freq = policy->max;
-
-#ifdef CONFIG_ARCH_OMAP1
- freqs.old = omap_getspeed(0);
- freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
- freqs.cpu = 0;
-
- if (freqs.old == freqs.new)
- return ret;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-#ifdef CONFIG_CPU_FREQ_DEBUG
- printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n",
- freqs.old, freqs.new);
-#endif
- ret = clk_set_rate(mpu_clk, freqs.new * 1000);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE)
- freq = target_freq * 1000;
- if (opp_find_freq_ceil(mpu_dev, &freq))
- omap_pm_cpu_set_freq(freq);
-#endif
- return ret;
-}
-
-static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
-{
- int result = 0;
-
- mpu_clk = clk_get(NULL, MPU_CLK);
- if (IS_ERR(mpu_clk))
- return PTR_ERR(mpu_clk);
-
- if (policy->cpu != 0)
- return -EINVAL;
-
- policy->cur = policy->min = policy->max = omap_getspeed(0);
-
- if (!cpu_is_omap34xx()) {
- clk_init_cpufreq_table(&freq_table);
- } else {
- struct device *mpu_dev = omap2_get_mpuss_device();
-
- opp_init_cpufreq_table(mpu_dev, &freq_table);
- }
-
- if (freq_table) {
- result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
- if (!result)
- cpufreq_frequency_table_get_attr(freq_table,
- policy->cpu);
- } else {
- policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
- policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
- VERY_HI_RATE) / 1000;
- }
-
- policy->min = policy->cpuinfo.min_freq;
- policy->max = policy->cpuinfo.max_freq;
- policy->cur = omap_getspeed(0);
-
- /* FIXME: what's the actual transition time? */
- policy->cpuinfo.transition_latency = 300 * 1000;
-
- return 0;
-}
-
-static int omap_cpu_exit(struct cpufreq_policy *policy)
-{
- clk_exit_cpufreq_table(&freq_table);
- clk_put(mpu_clk);
- return 0;
-}
-
-static struct freq_attr *omap_cpufreq_attr[] = {
- &cpufreq_freq_attr_scaling_available_freqs,
- NULL,
-};
-
-static struct cpufreq_driver omap_driver = {
- .flags = CPUFREQ_STICKY,
- .verify = omap_verify_speed,
- .target = omap_target,
- .get = omap_getspeed,
- .init = omap_cpu_init,
- .exit = omap_cpu_exit,
- .name = "omap",
- .attr = omap_cpufreq_attr,
-};
-
-static int __init omap_cpufreq_init(void)
-{
- return cpufreq_register_driver(&omap_driver);
-}
-
-late_initcall(omap_cpufreq_init);
-
-/*
- * if ever we want to remove this, upon cleanup call:
- *
- * cpufreq_unregister_driver()
- * cpufreq_frequency_table_put_attr()
- */
-
--
1.6.6.1
@@ -1,170 +0,0 @@
From f375d3c39d2835929d34c2a046b8c43cea6d1467 Mon Sep 17 00:00:00 2001
From: Santosh Shilimkar <santosh.shilimkar@ti.com>
Date: Mon, 14 Mar 2011 17:08:49 +0530
Subject: [PATCH 7/8] OMAP2PLUS: cpufreq: Add SMP support to cater OMAP4430
On OMAP SMP configuartion, both processors share the voltage
and clock. So both CPUs needs to be scaled together and hence
needs software co-ordination.
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
cc: Vishwanath BS <vishwanath.bs@ti.com>
---
arch/arm/mach-omap2/omap2plus-cpufreq.c | 73 ++++++++++++++++++++++++++-----
1 files changed, 62 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index 14f84cc..8d472f6 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -26,9 +26,11 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/opp.h>
+#include <linux/cpu.h>
#include <asm/system.h>
#include <asm/smp_plat.h>
+#include <asm/cpu.h>
#include <plat/clock.h>
#include <plat/omap-pm.h>
@@ -63,7 +65,7 @@ static unsigned int omap_getspeed(unsigned int cpu)
{
unsigned long rate;
- if (cpu)
+ if (cpu >= NR_CPUS)
return 0;
rate = clk_get_rate(mpu_clk) / 1000;
@@ -74,9 +76,13 @@ static int omap_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
- int ret = 0;
+ int i, ret = 0;
struct cpufreq_freqs freqs;
+ /* Changes not allowed until all CPUs are online */
+ if (is_smp() && (num_online_cpus() < NR_CPUS))
+ return ret;
+
/* Ensure desired rate is within allowed range. Some govenors
* (ondemand) will just pass target_freq=0 to get the minimum. */
if (target_freq < policy->min)
@@ -84,15 +90,25 @@ static int omap_target(struct cpufreq_policy *policy,
if (target_freq > policy->max)
target_freq = policy->max;
- freqs.old = omap_getspeed(0);
+ freqs.old = omap_getspeed(policy->cpu);
freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
- freqs.cpu = 0;
+ freqs.cpu = policy->cpu;
if (freqs.old == freqs.new)
return ret;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ if (!is_smp()) {
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ goto set_freq;
+ }
+
+ /* notifiers */
+ for_each_cpu(i, policy->cpus) {
+ freqs.cpu = i;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ }
+set_freq:
#ifdef CONFIG_CPU_FREQ_DEBUG
pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
#endif
@@ -105,12 +121,33 @@ static int omap_target(struct cpufreq_policy *policy,
* CONFIG_SMP enabled. Below code is added only to manage that
* scenario
*/
- if (!is_smp())
+ freqs.new = omap_getspeed(policy->cpu);
+ if (!is_smp()) {
loops_per_jiffy =
cpufreq_scale(loops_per_jiffy, freqs.old, freqs.new);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ goto skip_lpj;
+ }
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+#ifdef CONFIG_SMP
+ /*
+ * Note that loops_per_jiffy is not updated on SMP systems in
+ * cpufreq driver. So, update the per-CPU loops_per_jiffy value
+ * on frequency transition. We need to update all dependent CPUs.
+ */
+ for_each_cpu(i, policy->cpus)
+ per_cpu(cpu_data, i).loops_per_jiffy =
+ cpufreq_scale(per_cpu(cpu_data, i).loops_per_jiffy,
+ freqs.old, freqs.new);
+#endif
+ /* notifiers */
+ for_each_cpu(i, policy->cpus) {
+ freqs.cpu = i;
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+
+skip_lpj:
return ret;
}
@@ -118,6 +155,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
struct device *mpu_dev;
+ static cpumask_var_t cpumask;
if (cpu_is_omap24xx())
mpu_clk = clk_get(NULL, "virt_prcm_set");
@@ -129,12 +167,12 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
if (IS_ERR(mpu_clk))
return PTR_ERR(mpu_clk);
- if (policy->cpu != 0)
+ if (policy->cpu >= NR_CPUS)
return -EINVAL;
- policy->cur = policy->min = policy->max = omap_getspeed(0);
-
+ policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
mpu_dev = omap2_get_mpuss_device();
+
if (!mpu_dev) {
pr_warning("%s: unable to get the mpu device\n", __func__);
return -EINVAL;
@@ -154,7 +192,20 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
- policy->cur = omap_getspeed(0);
+ policy->cur = omap_getspeed(policy->cpu);
+
+ /*
+ * On OMAP SMP configuartion, both processors share the voltage
+ * and clock. So both CPUs needs to be scaled together and hence
+ * needs software co-ordination. Use cpufreq affected_cpus
+ * interface to handle this scenario. Additional is_smp() check
+ * is to keep SMP_ON_UP build working.
+ */
+ if (is_smp()) {
+ policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+ cpumask_or(cpumask, cpumask_of(policy->cpu), cpumask);
+ cpumask_copy(policy->cpus, cpumask);
+ }
/* FIXME: what's the actual transition time? */
policy->cpuinfo.transition_latency = 300 * 1000;
--
1.6.6.1
@@ -1,29 +0,0 @@
From 6e101764a47cb6975a555e2237843ad391a542a4 Mon Sep 17 00:00:00 2001
From: Jarkko Nikula <jhnikula@gmail.com>
Date: Thu, 14 Apr 2011 16:21:58 +0300
Subject: [PATCH 8/8] OMAP2PLUS: cpufreq: Fix typo when attempting to set mpu_clk for OMAP4
Fix this typo as there is no dpll_mpu_ck for OMAP3 and code flow is clearly
trying to set mpu_clk for OMAP4 for which this dpll_mpu_ck is available.
Signed-off-by: Jarkko Nikula <jhnikula@gmail.com>
---
arch/arm/mach-omap2/omap2plus-cpufreq.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c
index 8d472f6..d53ce23 100644
--- a/arch/arm/mach-omap2/omap2plus-cpufreq.c
+++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c
@@ -161,7 +161,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
mpu_clk = clk_get(NULL, "virt_prcm_set");
else if (cpu_is_omap34xx())
mpu_clk = clk_get(NULL, "dpll1_ck");
- else if (cpu_is_omap34xx())
+ else if (cpu_is_omap44xx())
mpu_clk = clk_get(NULL, "dpll_mpu_ck");
if (IS_ERR(mpu_clk))
--
1.6.6.1
@@ -1,77 +0,0 @@
From 988f50cb51d18e81ed2f7673a09694d28c9d086a Mon Sep 17 00:00:00 2001
From: Rajendra Nayak <rnayak@ti.com>
Date: Tue, 5 Apr 2011 15:22:31 +0530
Subject: [PATCH 1/6] OMAP2+: clockdomain: Add an api to read idle mode
Add a clockdomain api to check if hardware supervised
idle transitions are enabled on a clockdomain.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
---
arch/arm/mach-omap2/clockdomain.c | 21 +++++++++++++++++++++
arch/arm/mach-omap2/clockdomain.h | 3 +++
2 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 6cb6c03..2ab3686 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -795,6 +795,27 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
arch_clkdm->clkdm_deny_idle(clkdm);
}
+/**
+ * clkdm_is_idle - Check if the clkdm hwsup/autoidle is enabled
+ * @clkdm: struct clockdomain *
+ *
+ * Returns true if the clockdomain is in hardware-supervised
+ * idle mode, or 0 otherwise.
+ *
+ */
+int clkdm_is_idle(struct clockdomain *clkdm)
+{
+ if (!clkdm)
+ return -EINVAL;
+
+ if (!arch_clkdm || !arch_clkdm->clkdm_is_idle)
+ return -EINVAL;
+
+ pr_debug("clockdomain: reading idle state for %s\n", clkdm->name);
+
+ return arch_clkdm->clkdm_is_idle(clkdm);
+}
+
/* Clockdomain-to-clock framework interface code */
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h
index 5823584..085ed82 100644
--- a/arch/arm/mach-omap2/clockdomain.h
+++ b/arch/arm/mach-omap2/clockdomain.h
@@ -138,6 +138,7 @@ struct clockdomain {
* @clkdm_wakeup: Force a clockdomain to wakeup
* @clkdm_allow_idle: Enable hw supervised idle transitions for clock domain
* @clkdm_deny_idle: Disable hw supervised idle transitions for clock domain
+ * @clkdm_is_idle: Check if hw supervised idle transitions are enabled
* @clkdm_clk_enable: Put the clkdm in right state for a clock enable
* @clkdm_clk_disable: Put the clkdm in right state for a clock disable
*/
@@ -154,6 +155,7 @@ struct clkdm_ops {
int (*clkdm_wakeup)(struct clockdomain *clkdm);
void (*clkdm_allow_idle)(struct clockdomain *clkdm);
void (*clkdm_deny_idle)(struct clockdomain *clkdm);
+ int (*clkdm_is_idle)(struct clockdomain *clkdm);
int (*clkdm_clk_enable)(struct clockdomain *clkdm);
int (*clkdm_clk_disable)(struct clockdomain *clkdm);
};
@@ -177,6 +179,7 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm);
void clkdm_allow_idle(struct clockdomain *clkdm);
void clkdm_deny_idle(struct clockdomain *clkdm);
+int clkdm_is_idle(struct clockdomain *clkdm);
int clkdm_wakeup(struct clockdomain *clkdm);
int clkdm_sleep(struct clockdomain *clkdm);
--
1.6.6.1
@@ -1,86 +0,0 @@
From e3ba8d41bfafd782f3ee7f8930d9bf393986c662 Mon Sep 17 00:00:00 2001
From: Rajendra Nayak <rnayak@ti.com>
Date: Tue, 5 Apr 2011 15:22:36 +0530
Subject: [PATCH 2/6] OMAP2+: clockdomain: Add SoC support for clkdm_is_idle
Add the SoC specific implemenation for clkdm_is_idle
for OMAP2/3 and OMAP4.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
---
arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | 12 ++++++++++++
arch/arm/mach-omap2/clockdomain44xx.c | 7 +++++++
2 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
index 48d0db7..db49baa 100644
--- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
@@ -13,6 +13,7 @@
*/
#include <linux/types.h>
+#include <linux/errno.h>
#include <plat/prcm.h>
#include "prm.h"
#include "prm2xxx_3xxx.h"
@@ -146,6 +147,15 @@ static void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
_clkdm_del_autodeps(clkdm);
}
+static int omap2_clkdm_is_idle(struct clockdomain *clkdm)
+{
+ if (!clkdm->clktrctrl_mask)
+ return -1;
+
+ return omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
+ clkdm->clktrctrl_mask);
+}
+
static void _enable_hwsup(struct clockdomain *clkdm)
{
if (cpu_is_omap24xx())
@@ -252,6 +262,7 @@ struct clkdm_ops omap2_clkdm_operations = {
.clkdm_wakeup = omap2_clkdm_wakeup,
.clkdm_allow_idle = omap2_clkdm_allow_idle,
.clkdm_deny_idle = omap2_clkdm_deny_idle,
+ .clkdm_is_idle = omap2_clkdm_is_idle,
.clkdm_clk_enable = omap2_clkdm_clk_enable,
.clkdm_clk_disable = omap2_clkdm_clk_disable,
};
@@ -269,6 +280,7 @@ struct clkdm_ops omap3_clkdm_operations = {
.clkdm_wakeup = omap3_clkdm_wakeup,
.clkdm_allow_idle = omap3_clkdm_allow_idle,
.clkdm_deny_idle = omap3_clkdm_deny_idle,
+ .clkdm_is_idle = omap2_clkdm_is_idle,
.clkdm_clk_enable = omap2_clkdm_clk_enable,
.clkdm_clk_disable = omap2_clkdm_clk_disable,
};
diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c
index a1a4ecd..4b10727 100644
--- a/arch/arm/mach-omap2/clockdomain44xx.c
+++ b/arch/arm/mach-omap2/clockdomain44xx.c
@@ -93,6 +93,12 @@ static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
clkdm->cm_inst, clkdm->clkdm_offs);
}
+static int omap4_clkdm_is_idle(struct clockdomain *clkdm)
+{
+ return omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
+ clkdm->cm_inst, clkdm->clkdm_offs);
+}
+
static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
{
bool hwsup = false;
@@ -132,6 +138,7 @@ struct clkdm_ops omap4_clkdm_operations = {
.clkdm_wakeup = omap4_clkdm_wakeup,
.clkdm_allow_idle = omap4_clkdm_allow_idle,
.clkdm_deny_idle = omap4_clkdm_deny_idle,
+ .clkdm_is_idle = omap4_clkdm_is_idle,
.clkdm_clk_enable = omap4_clkdm_clk_enable,
.clkdm_clk_disable = omap4_clkdm_clk_disable,
};
--
1.6.6.1
@@ -1,35 +0,0 @@
From 7cdc87071a4bb390ad5d7ddea210bd2b4d662114 Mon Sep 17 00:00:00 2001
From: Rajendra Nayak <rnayak@ti.com>
Date: Tue, 5 Apr 2011 15:22:41 +0530
Subject: [PATCH 3/6] OMAP2+: PM: Initialise sleep_switch to a non-valid value
sleep_switch which is initialised to 0 in omap_set_pwrdm_state
happens to be a valid sleep_switch type (FORCEWAKEUP_SWITCH)
which are defined as
#define FORCEWAKEUP_SWITCH 0
#define LOWPOWERSTATE_SWITCH 1
This causes the function to wrongly program some clock domains
even when the Powerdomain is in ON state.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
---
arch/arm/mach-omap2/pm.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 49486f5..d48813f 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -106,7 +106,7 @@ static void omap2_init_processor_devices(void)
int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
{
u32 cur_state;
- int sleep_switch = 0;
+ int sleep_switch = -1;
int ret = 0;
if (pwrdm == NULL || IS_ERR(pwrdm))
--
1.6.6.1
@@ -1,50 +0,0 @@
From cec133850aa42c03d912c764aaa441677e782eca Mon Sep 17 00:00:00 2001
From: Rajendra Nayak <rnayak@ti.com>
Date: Tue, 5 Apr 2011 15:22:48 +0530
Subject: [PATCH 4/6] OMAP2+: PM: idle clkdms only if already in idle
The omap_set_pwrdm_state function forces clockdomains
to idle, without checking the existing idle state
programmed, instead based solely on the HW capability
of the clockdomain to support idle.
This is wrong and the clockdomains should be idled
post a state_switch *only* if idle transitions on the
clockdomain were already enabled.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
---
arch/arm/mach-omap2/pm.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index d48813f..840b0e1 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -108,6 +108,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
u32 cur_state;
int sleep_switch = -1;
int ret = 0;
+ int hwsup = 0;
if (pwrdm == NULL || IS_ERR(pwrdm))
return -EINVAL;
@@ -127,6 +128,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
sleep_switch = LOWPOWERSTATE_SWITCH;
} else {
+ hwsup = clkdm_is_idle(pwrdm->pwrdm_clkdms[0]);
clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
pwrdm_wait_transition(pwrdm);
sleep_switch = FORCEWAKEUP_SWITCH;
@@ -142,7 +144,7 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
switch (sleep_switch) {
case FORCEWAKEUP_SWITCH:
- if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO)
+ if (hwsup)
clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
else
clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
--
1.6.6.1
@@ -1,46 +0,0 @@
From 8fb6b7c488b31fbff5b81bdeea5dbb236342458b Mon Sep 17 00:00:00 2001
From: Rajendra Nayak <rnayak@ti.com>
Date: Tue, 29 Mar 2011 22:37:43 +0530
Subject: [PATCH 5/6] OMAP2+: hwmod: Follow the recomended PRCM sequence
Follow the recomended PRCM sequence.
This still does not take care of Optional clocks.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
---
arch/arm/mach-omap2/omap_hwmod.c | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e034294..fc0db0c 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1223,6 +1223,7 @@ static int _reset(struct omap_hwmod *oh)
static int _enable(struct omap_hwmod *oh)
{
int r;
+ int hwsup = 0;
if (oh->_state != _HWMOD_STATE_INITIALIZED &&
oh->_state != _HWMOD_STATE_IDLE &&
@@ -1250,10 +1251,16 @@ static int _enable(struct omap_hwmod *oh)
omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
_add_initiator_dep(oh, mpu_oh);
+ if (oh->_clk && oh->_clk->clkdm) {
+ hwsup = clkdm_is_idle(oh->_clk->clkdm);
+ clkdm_wakeup(oh->_clk->clkdm);
+ }
_enable_clocks(oh);
-
r = _wait_target_ready(oh);
if (!r) {
+ if (oh->_clk && oh->_clk->clkdm && hwsup)
+ clkdm_allow_idle(oh->_clk->clkdm);
+
oh->_state = _HWMOD_STATE_ENABLED;
/* Access the sysconfig only if the target is ready */
--
1.6.6.1
@@ -1,33 +0,0 @@
From 7b74888d198c260992349fab214cad3adf853ef9 Mon Sep 17 00:00:00 2001
From: Rajendra Nayak <rnayak@ti.com>
Date: Tue, 2 Mar 2010 17:25:30 +0530
Subject: [PATCH 6/6] OMAP: Serial: Check wk_st only if present
Uart on the resume path tries to read wk_st registers, even
on architectures were its not present/populated.
This patch fixes the issue.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
---
arch/arm/mach-omap2/serial.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 1ac361b..a0046ce 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -418,8 +418,9 @@ void omap_uart_resume_idle(int num)
}
/* Check for normal UART wakeup */
- if (__raw_readl(uart->wk_st) & uart->wk_mask)
- omap_uart_block_sleep(uart);
+ if (uart->wk_st && uart->wk_mask)
+ if (__raw_readl(uart->wk_st) & uart->wk_mask)
+ omap_uart_block_sleep(uart);
return;
}
}
--
1.6.6.1
@@ -1,30 +0,0 @@
From 4af697edf9d1d85d2735e86e86e1203c3509dcba Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Sat, 12 Feb 2011 17:27:14 +0530
Subject: [PATCH 01/12] OMAP3+: voltage: remove spurious pr_notice for debugfs
cat of debugfs entry for vp_volt provides voltage. The additional pr_notice
is just spam on console and provides no additional information.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/voltage.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 0c1552d..9ef3789 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -148,7 +148,6 @@ static int vp_volt_debug_get(void *data, u64 *val)
}
vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage);
- pr_notice("curr_vsel = %x\n", vsel);
if (!vdd->pmic_info->vsel_to_uv) {
pr_warning("PMIC function to convert vsel to voltage"
--
1.6.6.1
@@ -1,41 +0,0 @@
From 37fb1c8eeecd39542716d3d0c7c5e3ca0eb198f8 Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Sun, 13 Mar 2011 09:07:23 +0530
Subject: [PATCH 02/12] OMAP4: PM: remove redundant #ifdef CONFIG_PM
pm44xx.c is built only when CONFIG_PM is setup,
remove redundant CONFIG_PM check.
This also fixes:
https://bugzilla.kernel.org/show_bug.cgi?id=25022
Reported-by: Martin Etti <ettl.martin@gmx.de>
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/pm44xx.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 76cfff2..59a870b 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -105,13 +105,11 @@ static int __init omap4_pm_init(void)
pr_err("Power Management for TI OMAP4.\n");
-#ifdef CONFIG_PM
ret = pwrdm_for_each(pwrdms_setup, NULL);
if (ret) {
pr_err("Failed to setup powerdomains\n");
goto err2;
}
-#endif
#ifdef CONFIG_SUSPEND
suspend_set_ops(&omap_pm_ops);
--
1.6.6.1
@@ -1,30 +0,0 @@
From a22a0dcefe99c8ee260e0c489bc44e6e14bb1ccb Mon Sep 17 00:00:00 2001
From: Aaro Koskinen <aaro.koskinen@nokia.com>
Date: Thu, 24 Mar 2011 18:35:31 +0200
Subject: [PATCH 03/12] OMAP3+: smartreflex: fix sr_late_init() error path in probe
sr_late_init() will take care of freeing the resources.
Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/smartreflex.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 13e24f9..dbc4b6f 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -883,7 +883,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
ret = sr_late_init(sr_info);
if (ret) {
pr_warning("%s: Error in SR late init\n", __func__);
- goto err_release_region;
+ return ret;
}
}
--
1.6.6.1
@@ -1,36 +0,0 @@
From db9c7da6a78be8584c96c83a3a2d1c8aeb623da8 Mon Sep 17 00:00:00 2001
From: Aaro Koskinen <aaro.koskinen@nokia.com>
Date: Thu, 24 Mar 2011 18:35:32 +0200
Subject: [PATCH 04/12] OMAP3+: smartreflex: request the memory region
We are releasing the memory region, but never actually request it.
Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/smartreflex.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index dbc4b6f..703143a 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -847,6 +847,14 @@ static int __init omap_sr_probe(struct platform_device *pdev)
goto err_free_devinfo;
}
+ mem = request_mem_region(mem->start, resource_size(mem),
+ dev_name(&pdev->dev));
+ if (!mem) {
+ dev_err(&pdev->dev, "%s: no mem region\n", __func__);
+ ret = -EBUSY;
+ goto err_free_devinfo;
+ }
+
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
pm_runtime_enable(&pdev->dev);
--
1.6.6.1
@@ -1,66 +0,0 @@
From b3ca51ac09da7c260c28df396d4c830814697ff0 Mon Sep 17 00:00:00 2001
From: Aaro Koskinen <aaro.koskinen@nokia.com>
Date: Thu, 24 Mar 2011 18:35:33 +0200
Subject: [PATCH 05/12] OMAP3+: smartreflex: fix ioremap leak on probe error
Add missing iounmap() to error paths.
Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/smartreflex.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 703143a..156807e 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -904,7 +904,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
vdd_dbg_dir = omap_voltage_get_dbgdir(sr_info->voltdm);
if (!vdd_dbg_dir) {
ret = -EINVAL;
- goto err_release_region;
+ goto err_iounmap;
}
sr_info->dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir);
@@ -912,7 +912,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
__func__);
ret = PTR_ERR(sr_info->dbg_dir);
- goto err_release_region;
+ goto err_iounmap;
}
(void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
@@ -929,7 +929,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
"for n-values\n", __func__);
ret = PTR_ERR(nvalue_dir);
- goto err_release_region;
+ goto err_iounmap;
}
omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
@@ -939,7 +939,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
"entries for n-values\n",
__func__, sr_info->voltdm->name);
ret = -ENODATA;
- goto err_release_region;
+ goto err_iounmap;
}
for (i = 0; i < sr_info->nvalue_count; i++) {
@@ -953,6 +953,8 @@ static int __init omap_sr_probe(struct platform_device *pdev)
return ret;
+err_iounmap:
+ iounmap(sr_info->base);
err_release_region:
release_mem_region(mem->start, resource_size(mem));
err_free_devinfo:
--
1.6.6.1
@@ -1,29 +0,0 @@
From 92e63a2f098ce344cfc51ec9a7420e1a5cf85c3e Mon Sep 17 00:00:00 2001
From: Aaro Koskinen <aaro.koskinen@nokia.com>
Date: Thu, 24 Mar 2011 18:35:34 +0200
Subject: [PATCH 06/12] OMAP3+: smartreflex: delete instance from sr_list on probe error
If the probe fails, the node should be deleted from sr_list.
Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/smartreflex.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 156807e..f0a488a 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -954,6 +954,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
return ret;
err_iounmap:
+ list_del(&sr_info->node);
iounmap(sr_info->base);
err_release_region:
release_mem_region(mem->start, resource_size(mem));
--
1.6.6.1
@@ -1,48 +0,0 @@
From c194377152df812bcb29fff8f217ffbde59089be Mon Sep 17 00:00:00 2001
From: Aaro Koskinen <aaro.koskinen@nokia.com>
Date: Thu, 24 Mar 2011 18:35:35 +0200
Subject: [PATCH 07/12] OMAP3+: smartreflex: delete debugfs entries on probe error
Delete created debugfs entries if probe fails.
Signed-off-by: Aaro Koskinen <aaro.koskinen@nokia.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/smartreflex.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index f0a488a..fb7dc52 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -929,7 +929,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
"for n-values\n", __func__);
ret = PTR_ERR(nvalue_dir);
- goto err_iounmap;
+ goto err_debugfs;
}
omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
@@ -939,7 +939,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
"entries for n-values\n",
__func__, sr_info->voltdm->name);
ret = -ENODATA;
- goto err_iounmap;
+ goto err_debugfs;
}
for (i = 0; i < sr_info->nvalue_count; i++) {
@@ -953,6 +953,8 @@ static int __init omap_sr_probe(struct platform_device *pdev)
return ret;
+err_debugfs:
+ debugfs_remove_recursive(sr_info->dbg_dir);
err_iounmap:
list_del(&sr_info->node);
iounmap(sr_info->base);
--
1.6.6.1
@@ -1,57 +0,0 @@
From 2b9e07516cc3853340b5e06e9ae7244ca5681466 Mon Sep 17 00:00:00 2001
From: Jean Pihet <j-pihet@ti.com>
Date: Fri, 29 Apr 2011 11:26:22 +0200
Subject: [PATCH 08/12] OMAP3 cpuidle: remove useless SDP specific timings
The cpuidle states settings can be overriden by some board-
specific settings, by calling omap3_pm_init_cpuidle.
Remove the 3430SDP specific states settings registration
since the figures are identical to the default ones (in cpuidle34xx.c).
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/board-3430sdp.c | 19 -------------------
1 files changed, 0 insertions(+), 19 deletions(-)
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 9afd087..7ffad7b 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -59,24 +59,6 @@
#define TWL4030_MSECURE_GPIO 22
-/* FIXME: These values need to be updated based on more profiling on 3430sdp*/
-static struct cpuidle_params omap3_cpuidle_params_table[] = {
- /* C1 */
- {1, 2, 2, 5},
- /* C2 */
- {1, 10, 10, 30},
- /* C3 */
- {1, 50, 50, 300},
- /* C4 */
- {1, 1500, 1800, 4000},
- /* C5 */
- {1, 2500, 7500, 12000},
- /* C6 */
- {1, 3000, 8500, 15000},
- /* C7 */
- {1, 10000, 30000, 300000},
-};
-
static uint32_t board_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_RIGHT),
@@ -883,7 +865,6 @@ static void __init omap_3430sdp_init(void)
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
omap_board_config = sdp3430_config;
omap_board_config_size = ARRAY_SIZE(sdp3430_config);
- omap3_pm_init_cpuidle(omap3_cpuidle_params_table);
omap3430_i2c_init();
omap_display_init(&sdp3430_dss_data);
if (omap_rev() > OMAP3430_REV_ES1_0)
--
1.6.6.1
@@ -1,48 +0,0 @@
From a0f28097b944930e479998780863b9e5a39e30b3 Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Mon, 14 Feb 2011 12:16:36 +0530
Subject: [PATCH 09/12] OMAP3+: SR: make notify independent of class
Interrupt notification mechanism of SmartReflex can be used by the
choice of implementation of the class driver. For example, Class 2 and
Class 1.5 of SmartReflex can both use the interrupt notification to
identify the transition of voltage or other events.
Hence, the actual class does not matter for notifier. Let the class
driver's handling decide how it should be used. SmartReflex driver
should provide just the primitives.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/smartreflex.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index fb7dc52..3ee7261 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -143,7 +143,7 @@ static irqreturn_t sr_interrupt(int irq, void *data)
sr_write_reg(sr_info, IRQSTATUS, status);
}
- if (sr_class->class_type == SR_CLASS2 && sr_class->notify)
+ if (sr_class->notify)
sr_class->notify(sr_info->voltdm, status);
return IRQ_HANDLED;
@@ -258,9 +258,7 @@ static int sr_late_init(struct omap_sr *sr_info)
struct resource *mem;
int ret = 0;
- if (sr_class->class_type == SR_CLASS2 &&
- sr_class->notify_flags && sr_info->irq) {
-
+ if (sr_class->notify && sr_class->notify_flags && sr_info->irq) {
name = kasprintf(GFP_KERNEL, "sr_%s", sr_info->voltdm->name);
if (name == NULL) {
ret = -ENOMEM;
--
1.6.6.1
@@ -1,37 +0,0 @@
From ca5dc57538a566681731102e09a9d1865a4a7020 Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Mon, 14 Feb 2011 12:41:10 +0530
Subject: [PATCH 10/12] OMAP3+: SR: disable interrupt by default
We will enable and disable interrupt on a need basis in the class
driver. We need to keep the IRQ disabled by default else the
forceupdate or vcbypass events could trigger events that we don't
need/expect to handle.
This is a preparation for SmartReflex AVS class drivers such as
class 2 and class 1.5 which would need to use interrupts. Existing
SmartReflex AVS class 3 driver does not require to use interrupts
and is not impacted by this change.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/smartreflex.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 3ee7261..616ef62 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -268,6 +268,7 @@ static int sr_late_init(struct omap_sr *sr_info)
0, name, (void *)sr_info);
if (ret)
goto error;
+ disable_irq(sr_info->irq);
}
if (pdata && pdata->enable_on_init)
--
1.6.6.1
@@ -1,41 +0,0 @@
From 4aa67e94d6b13905abcf3e95cb66ea7be9c2e8dd Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Mon, 14 Feb 2011 21:14:17 +0530
Subject: [PATCH 11/12] OMAP3+: SR: enable/disable SR only on need
Since we already know the state of the autocomp enablement, we can
see if the requested state is different from the current state and
enable/disable SR only on the need basis.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/smartreflex.c | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 616ef62..3bd9fac 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -807,10 +807,13 @@ static int omap_sr_autocomp_store(void *data, u64 val)
return -EINVAL;
}
- if (!val)
- sr_stop_vddautocomp(sr_info);
- else
- sr_start_vddautocomp(sr_info);
+ /* control enable/disable only if there is a delta in value */
+ if (sr_info->autocomp_active != val) {
+ if (!val)
+ sr_stop_vddautocomp(sr_info);
+ else
+ sr_start_vddautocomp(sr_info);
+ }
return 0;
}
--
1.6.6.1
@@ -1,49 +0,0 @@
From 0c2089eecdfc3a85a376eddf9c77857f3d575be6 Mon Sep 17 00:00:00 2001
From: Nishanth Menon <nm@ti.com>
Date: Mon, 14 Feb 2011 12:33:13 +0530
Subject: [PATCH 12/12] OMAP3+: SR: fix cosmetic indentation
Error label case seems to have a 2 tab indentation when just 1 is
necessary.
Signed-off-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
arch/arm/mach-omap2/smartreflex.c | 20 ++++++++++----------
1 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 3bd9fac..2ce2fb7 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -277,16 +277,16 @@ static int sr_late_init(struct omap_sr *sr_info)
return ret;
error:
- iounmap(sr_info->base);
- mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0);
- release_mem_region(mem->start, resource_size(mem));
- list_del(&sr_info->node);
- dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
- "interrupt handler. Smartreflex will"
- "not function as desired\n", __func__);
- kfree(name);
- kfree(sr_info);
- return ret;
+ iounmap(sr_info->base);
+ mem = platform_get_resource(sr_info->pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, resource_size(mem));
+ list_del(&sr_info->node);
+ dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
+ "interrupt handler. Smartreflex will"
+ "not function as desired\n", __func__);
+ kfree(name);
+ kfree(sr_info);
+ return ret;
}
static void sr_v1_disable(struct omap_sr *sr)
--
1.6.6.1
@@ -1,33 +0,0 @@
From 6aae34d56ba8fef140b60631536272f6b39c1f61 Mon Sep 17 00:00:00 2001
From: Tomi Valkeinen <tomi.valkeinen@ti.com>
Date: Thu, 7 Apr 2011 15:28:47 +0300
Subject: [PATCH 01/32] OMAP: DSS2: DSI: fix use_sys_clk & highfreq
use_sys_clk and highfreq fields in dsi.current_cinfo were never set.
Luckily they weren't used anywhere so it didn't cause any problems.
This patch fixes those fields and they are now set at the same time as
the rest of the fields.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 0a7f1a4..8604153 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1276,6 +1276,9 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
DSSDBGF();
+ dsi.current_cinfo.use_sys_clk = cinfo->use_sys_clk;
+ dsi.current_cinfo.highfreq = cinfo->highfreq;
+
dsi.current_cinfo.fint = cinfo->fint;
dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk =
--
1.6.6.1
@@ -1,49 +0,0 @@
From 5275654d2e873ca5bdbbd8be61dbb2d63c0e04cb Mon Sep 17 00:00:00 2001
From: Tomi Valkeinen <tomi.valkeinen@ti.com>
Date: Mon, 4 Apr 2011 10:02:53 +0300
Subject: [PATCH 02/32] OMAP: DSS2: DSI: fix dsi_dump_clocks()
On OMAP4, reading DSI_PLL_CONFIGURATION2 register requires the L3 clock
(CIO_CLK_ICG) to PLL. Currently dsi_dump_clocks() tries to read that
register without enabling the L3 clock, leading to crash if DSI is not
in use.
The status of the bit being read from DSI_PLL_CONFIGURATION2 is
available from dsi_clock_info->use_sys_clk, so we can avoid the whole
problem by just using that.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 6 +-----
1 files changed, 1 insertions(+), 5 deletions(-)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 8604153..1464ac4 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1491,7 +1491,6 @@ void dsi_pll_uninit(void)
void dsi_dump_clocks(struct seq_file *s)
{
- int clksel;
struct dsi_clock_info *cinfo = &dsi.current_cinfo;
enum dss_clk_source dispc_clk_src, dsi_clk_src;
@@ -1500,13 +1499,10 @@ void dsi_dump_clocks(struct seq_file *s)
enable_clocks(1);
- clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
-
seq_printf(s, "- DSI PLL -\n");
seq_printf(s, "dsi pll source = %s\n",
- clksel == 0 ?
- "dss_sys_clk" : "pclkfree");
+ cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree");
seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
--
1.6.6.1
@@ -1,43 +0,0 @@
From 9ddb3aafff5f7f6b7eaad32f9b1eea249c0dce8b Mon Sep 17 00:00:00 2001
From: Archit Taneja <archit@ti.com>
Date: Thu, 31 Mar 2011 13:23:35 +0530
Subject: [PATCH 03/32] OMAP2PLUS: DSS2: Fix: Return correct lcd clock source for OMAP2/3
dss.lcd_clk_source is set to the default value DSS_CLK_SRC_FCK at dss_init.
For OMAP2 and OMAP3, the dss.lcd_clk_source should always be the same as
dss.dispc_clk_source. The function dss_get_lcd_clk_source() always returns the
default value DSS_CLK_SRC_FCK for OMAP2/3. This leads to wrong clock dumps when
dispc_clk_source is not DSS_CLK_SRC_FCK.
Correct this function to always return dss.dispc_clk_source for OMAP2/3.
Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dss.c | 10 ++++++++--
1 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 3f1fee6..c3b48a0 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -385,8 +385,14 @@ enum dss_clk_source dss_get_dsi_clk_source(void)
enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
{
- int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
- return dss.lcd_clk_source[ix];
+ if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
+ int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+ return dss.lcd_clk_source[ix];
+ } else {
+ /* LCD_CLK source is the same as DISPC_FCLK source for
+ * OMAP2 and OMAP3 */
+ return dss.dispc_clk_source;
+ }
}
/* calculate clock rates using dividers in cinfo */
--
1.6.6.1
@@ -1,64 +0,0 @@
From 4a56fbcabd128dbd07895e5167fd131299a1391c Mon Sep 17 00:00:00 2001
From: Tomi Valkeinen <tomi.valkeinen@ti.com>
Date: Fri, 15 Apr 2011 10:42:59 +0300
Subject: [PATCH 04/32] OMAP: DSS: DSI: Fix DSI PLL power bug
OMAP3630 has a HW bug causing DSI PLL power command POWER_ON_DIV (0x3)
to not work properly. The bug prevents us from enabling DSI PLL power
only to HS divider block.
This patch adds a dss feature for the bug and converts POWER_ON_DIV
requests to POWER_ON_ALL (0x2).
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 5 +++++
drivers/video/omap2/dss/dss_features.c | 2 +-
drivers/video/omap2/dss/dss_features.h | 2 ++
3 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 1464ac4..cbd9ca4 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1059,6 +1059,11 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
{
int t = 0;
+ /* DSI-PLL power command 0x3 is not working */
+ if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
+ state == DSI_PLL_POWER_ON_DIV)
+ state = DSI_PLL_POWER_ON_ALL;
+
REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
/* PLL_PWR_STATUS */
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index aa16222..8c50e18 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -271,7 +271,7 @@ static struct omap_dss_features omap3630_dss_features = {
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
- FEAT_RESIZECONF,
+ FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG,
.num_mgrs = 2,
.num_ovls = 3,
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index 12e9c4e..37922ce 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -40,6 +40,8 @@ enum dss_feat_id {
/* Independent core clk divider */
FEAT_CORE_CLK_DIV = 1 << 11,
FEAT_LCD_CLK_SRC = 1 << 12,
+ /* DSI-PLL power command 0x3 is not working */
+ FEAT_DSI_PLL_PWR_BUG = 1 << 13,
};
/* DSS register field id */
--
1.6.6.1
@@ -1,61 +0,0 @@
From fcb26a06fe1badfaaf7aaa68140c8b3370dd503e Mon Sep 17 00:00:00 2001
From: Tomi Valkeinen <tomi.valkeinen@ti.com>
Date: Fri, 8 Apr 2011 09:30:27 +0300
Subject: [PATCH 05/32] OMAP: DSS2: fix panel Kconfig dependencies
All DPI panels were missing dependency to OMAP2_DSS_DPI. Add the
dependency.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/displays/Kconfig | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index d18ad6b..609a280 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -3,6 +3,7 @@ menu "OMAP2/3 Display Device Drivers"
config PANEL_GENERIC_DPI
tristate "Generic DPI Panel"
+ depends on OMAP2_DSS_DPI
help
Generic DPI panel driver.
Supports DVI output for Beagle and OMAP3 SDP.
@@ -11,20 +12,20 @@ config PANEL_GENERIC_DPI
config PANEL_LGPHILIPS_LB035Q02
tristate "LG.Philips LB035Q02 LCD Panel"
- depends on OMAP2_DSS && SPI
+ depends on OMAP2_DSS_DPI && SPI
help
LCD Panel used on the Gumstix Overo Palo35
config PANEL_SHARP_LS037V7DW01
tristate "Sharp LS037V7DW01 LCD Panel"
- depends on OMAP2_DSS
+ depends on OMAP2_DSS_DPI
select BACKLIGHT_CLASS_DEVICE
help
LCD Panel used in TI's SDP3430 and EVM boards
config PANEL_NEC_NL8048HL11_01B
tristate "NEC NL8048HL11-01B Panel"
- depends on OMAP2_DSS
+ depends on OMAP2_DSS_DPI
help
This NEC NL8048HL11-01B panel is TFT LCD
used in the Zoom2/3/3630 sdp boards.
@@ -37,7 +38,7 @@ config PANEL_TAAL
config PANEL_TPO_TD043MTEA1
tristate "TPO TD043MTEA1 LCD Panel"
- depends on OMAP2_DSS && SPI
+ depends on OMAP2_DSS_DPI && SPI
help
LCD Panel used in OMAP3 Pandora
--
1.6.6.1
@@ -1,75 +0,0 @@
From 4bd1d52fff974f5a5d0582f4fa4eae6e03e36fc1 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Tue, 19 Jan 2010 21:19:15 -0800
Subject: [PATCH 06/32] OMAP: DSS2: add bootarg for selecting svideo or composite for tv output
also add pal-16 and ntsc-16 omapfb.mode settings for 16bpp
---
drivers/video/omap2/dss/venc.c | 22 ++++++++++++++++++++++
drivers/video/omap2/omapfb/omapfb-main.c | 10 +++++++++-
2 files changed, 31 insertions(+), 1 deletions(-)
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 8e35a5b..827723f 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -85,6 +85,11 @@
#define VENC_OUTPUT_TEST 0xC8
#define VENC_DAC_B__DAC_C 0xC8
+static char *tv_connection;
+
+module_param_named(tvcable, tv_connection, charp, 0);
+MODULE_PARM_DESC(tvcable, "TV connection type (svideo, composite)");
+
struct venc_config {
u32 f_control;
u32 vidout_ctrl;
@@ -458,6 +463,23 @@ static int venc_panel_probe(struct omap_dss_device *dssdev)
{
dssdev->panel.timings = omap_dss_pal_timings;
+ /* Allow the TV output to be overriden */
+ if (tv_connection) {
+ if (strcmp(tv_connection, "svideo") == 0) {
+ printk(KERN_INFO
+ "omapdss: tv output is svideo.\n");
+ dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
+ } else if (strcmp(tv_connection, "composite") == 0) {
+ printk(KERN_INFO
+ "omapdss: tv output is composite.\n");
+ dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
+ } else {
+ printk(KERN_INFO
+ "omapdss: unsupported output type'%s'.\n",
+ tv_connection);
+ }
+ }
+
return 0;
}
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 505ec66..eaeded5 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -2036,7 +2036,15 @@ static int omapfb_mode_to_timings(const char *mode_str,
int r;
#ifdef CONFIG_OMAP2_DSS_VENC
- if (strcmp(mode_str, "pal") == 0) {
+ if (strcmp(mode_str, "pal-16") == 0) {
+ *timings = omap_dss_pal_timings;
+ *bpp = 16;
+ return 0;
+ } else if (strcmp(mode_str, "ntsc-16") == 0) {
+ *timings = omap_dss_ntsc_timings;
+ *bpp = 16;
+ return 0;
+ } else if (strcmp(mode_str, "pal") == 0) {
*timings = omap_dss_pal_timings;
*bpp = 24;
return 0;
--
1.6.6.1
@@ -1,27 +0,0 @@
From 6d87a3f85ac36205111b4fe71ad06976239cdbe7 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Sat, 19 Dec 2009 06:52:43 -0800
Subject: [PATCH 07/32] video: add timings for hd720
---
drivers/video/modedb.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 48c3ea8..b320a30 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -103,6 +103,10 @@ static const struct fb_videomode modedb[] = {
{ NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0,
FB_VMODE_NONINTERLACED },
+ /* 1280x720 @ 60 Hz, 45 kHz hsync, CEA 681-E Format 4 */
+ { "hd720", 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5, 0,
+ FB_VMODE_NONINTERLACED },
+
/* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
{ NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, 0,
FB_VMODE_INTERLACED },
--
1.6.6.1
@@ -1,29 +0,0 @@
From 1e3fcfd74686fa8b02f93bb592cca458942058e4 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <sakoman@gmail.com>
Date: Tue, 15 Dec 2009 15:17:44 -0800
Subject: [PATCH 08/32] drivers: net: smsc911x: return ENODEV if device is not found
Signed-off-by: Steve Sakoman <sakoman@gmail.com>
---
drivers/net/smsc911x.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index 4b42ecc..5c1202b 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -2028,8 +2028,10 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
}
retval = smsc911x_init(dev);
- if (retval < 0)
+ if (retval < 0) {
+ retval = -ENODEV;
goto out_unmap_io_3;
+ }
/* configure irq polarity and type before connecting isr */
if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
--
1.6.6.1
@@ -1,47 +0,0 @@
From 078005a9c8b5913ed5eb7a7a9508e4b0a5b18c30 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <sakoman@gmail.com>
Date: Tue, 15 Dec 2009 15:24:10 -0800
Subject: [PATCH 09/32] drivers: input: touchscreen: ads7846: return ENODEV if device is not found
Signed-off-by: Steve Sakoman <sakoman@gmail.com>
---
drivers/input/touchscreen/ads7846.c | 13 ++++++++++---
1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 1de1c19..097db10 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -1338,11 +1338,18 @@ static int __devinit ads7846_probe(struct spi_device *spi)
* the touchscreen, in case it's not connected.
*/
if (ts->model == 7845)
- ads7845_read12_ser(&spi->dev, PWRDOWN);
+ err = ads7845_read12_ser(&spi->dev, PWRDOWN);
else
- (void) ads7846_read12_ser(&spi->dev,
+ err = ads7846_read12_ser(&spi->dev,
READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+ /* if sample is all 0's or all 1's then there is no device on spi */
+ if ( (err == 0x000) || (err == 0xfff)) {
+ dev_info(&spi->dev, "no device detected, test read result was 0x%08X\n", err);
+ err = -ENODEV;
+ goto err_free_irq;
+ }
+
err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
if (err)
goto err_remove_hwmon;
@@ -1366,7 +1373,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
err_put_regulator:
regulator_put(ts->reg);
err_free_gpio:
- if (!ts->get_pendown_state)
+ if (!ts->get_pendown_state && ts->gpio_pendown != -1)
gpio_free(ts->gpio_pendown);
err_cleanup_filter:
if (ts->filter_cleanup)
--
1.6.6.1
@@ -1,25 +0,0 @@
From ae16b19238b8d0609612d0e1f1a419d293f17c80 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Thu, 3 Mar 2011 13:29:30 -0800
Subject: [PATCH 10/32] Revert "omap2_mcspi: Flush posted writes"
This reverts commit a330ce2001b290c59fe98c37e981683ef0a75fdf.
---
drivers/spi/omap2_mcspi.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index 6f86ba0..6094be7 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -195,7 +195,6 @@ static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
cs->chconf0 = val;
mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val);
- mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
}
static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
--
1.6.6.1
@@ -1,482 +0,0 @@
From 3a66cefdf60033381c623b0425345c41e8c078fe Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Fri, 19 Nov 2010 15:11:19 -0800
Subject: [PATCH 11/32] Revert "omap_hsmmc: improve interrupt synchronisation"
This reverts commit b417577d3b9bbb06a4ddc9aa955af9bd503f7242.
Conflicts:
drivers/mmc/host/omap_hsmmc.c
---
drivers/mmc/host/omap_hsmmc.c | 267 ++++++++++++++++++++---------------------
1 files changed, 128 insertions(+), 139 deletions(-)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 259ece0..15a023b 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -159,10 +159,12 @@ struct omap_hsmmc_host {
*/
struct regulator *vcc;
struct regulator *vcc_aux;
+ struct semaphore sem;
struct work_struct mmc_carddetect_work;
void __iomem *base;
resource_size_t mapbase;
spinlock_t irq_lock; /* Prevent races with irq handler */
+ unsigned long flags;
unsigned int id;
unsigned int dma_len;
unsigned int dma_sg_idx;
@@ -183,7 +185,6 @@ struct omap_hsmmc_host {
int protect_card;
int reqs_blocked;
int use_reg;
- int req_in_progress;
struct omap_mmc_platform_data *pdata;
};
@@ -556,32 +557,6 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
}
-static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
- struct mmc_command *cmd)
-{
- unsigned int irq_mask;
-
- if (host->use_dma)
- irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
- else
- irq_mask = INT_EN_MASK;
-
- /* Disable timeout for erases */
- if (cmd->opcode == MMC_ERASE)
- irq_mask &= ~DTO_ENABLE;
-
- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
- OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
- OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
-}
-
-static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
-{
- OMAP_HSMMC_WRITE(host->base, ISE, 0);
- OMAP_HSMMC_WRITE(host->base, IE, 0);
- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
-}
-
#ifdef CONFIG_PM
/*
@@ -650,7 +625,9 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
&& time_before(jiffies, timeout))
;
- omap_hsmmc_disable_irq(host);
+ OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
/* Do not initialize card-specific things if the power is off */
if (host->power_mode == MMC_POWER_OFF)
@@ -753,8 +730,6 @@ static void send_init_stream(struct omap_hsmmc_host *host)
return;
disable_irq(host->irq);
-
- OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
@@ -820,7 +795,17 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
host->cmd = cmd;
- omap_hsmmc_enable_irq(host, cmd);
+ /*
+ * Clear status bits and enable interrupts
+ */
+ OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+
+ if (host->use_dma)
+ OMAP_HSMMC_WRITE(host->base, IE,
+ INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
+ else
+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
host->response_busy = 0;
if (cmd->flags & MMC_RSP_PRESENT) {
@@ -854,7 +839,13 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
if (host->use_dma)
cmdreg |= DMA_EN;
- host->req_in_progress = 1;
+ /*
+ * In an interrupt context (i.e. STOP command), the spinlock is unlocked
+ * by the interrupt handler, otherwise (i.e. for a new request) it is
+ * unlocked here.
+ */
+ if (!in_interrupt())
+ spin_unlock_irqrestore(&host->irq_lock, host->flags);
OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
@@ -869,23 +860,6 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
return DMA_FROM_DEVICE;
}
-static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
-{
- int dma_ch;
-
- spin_lock(&host->irq_lock);
- host->req_in_progress = 0;
- dma_ch = host->dma_ch;
- spin_unlock(&host->irq_lock);
-
- omap_hsmmc_disable_irq(host);
- /* Do not complete the request if DMA is still in progress */
- if (mrq->data && host->use_dma && dma_ch != -1)
- return;
- host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
-}
-
/*
* Notify the transfer complete to MMC core
*/
@@ -902,19 +876,25 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
return;
}
- omap_hsmmc_request_done(host, mrq);
+ host->mrq = NULL;
+ mmc_request_done(host->mmc, mrq);
return;
}
host->data = NULL;
+ if (host->use_dma && host->dma_ch != -1)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+ omap_hsmmc_get_dma_dir(host, data));
+
if (!data->error)
data->bytes_xfered += data->blocks * (data->blksz);
else
data->bytes_xfered = 0;
if (!data->stop) {
- omap_hsmmc_request_done(host, data->mrq);
+ host->mrq = NULL;
+ mmc_request_done(host->mmc, data->mrq);
return;
}
omap_hsmmc_start_command(host, data->stop, NULL);
@@ -940,8 +920,10 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
}
}
- if ((host->data == NULL && !host->response_busy) || cmd->error)
- omap_hsmmc_request_done(host, cmd->mrq);
+ if ((host->data == NULL && !host->response_busy) || cmd->error) {
+ host->mrq = NULL;
+ mmc_request_done(host->mmc, cmd->mrq);
+ }
}
/*
@@ -949,19 +931,14 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
*/
static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
{
- int dma_ch;
-
host->data->error = errno;
- spin_lock(&host->irq_lock);
- dma_ch = host->dma_ch;
- host->dma_ch = -1;
- spin_unlock(&host->irq_lock);
-
- if (host->use_dma && dma_ch != -1) {
+ if (host->use_dma && host->dma_ch != -1) {
dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
omap_hsmmc_get_dma_dir(host, host->data));
- omap_free_dma(dma_ch);
+ omap_free_dma(host->dma_ch);
+ host->dma_ch = -1;
+ up(&host->sem);
}
host->data = NULL;
}
@@ -1034,21 +1011,28 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
__func__);
}
-static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
+/*
+ * MMC controller IRQ handler
+ */
+static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
{
+ struct omap_hsmmc_host *host = dev_id;
struct mmc_data *data;
- int end_cmd = 0, end_trans = 0;
-
- if (!host->req_in_progress) {
- do {
- OMAP_HSMMC_WRITE(host->base, STAT, status);
- /* Flush posted write */
- status = OMAP_HSMMC_READ(host->base, STAT);
- } while (status & INT_EN_MASK);
- return;
+ int end_cmd = 0, end_trans = 0, status;
+
+ spin_lock(&host->irq_lock);
+
+ if (host->mrq == NULL) {
+ OMAP_HSMMC_WRITE(host->base, STAT,
+ OMAP_HSMMC_READ(host->base, STAT));
+ /* Flush posted write */
+ OMAP_HSMMC_READ(host->base, STAT);
+ spin_unlock(&host->irq_lock);
+ return IRQ_HANDLED;
}
data = host->data;
+ status = OMAP_HSMMC_READ(host->base, STAT);
dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
if (status & ERR) {
@@ -1101,27 +1085,15 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
}
OMAP_HSMMC_WRITE(host->base, STAT, status);
+ /* Flush posted write */
+ OMAP_HSMMC_READ(host->base, STAT);
if (end_cmd || ((status & CC) && host->cmd))
omap_hsmmc_cmd_done(host, host->cmd);
if ((end_trans || (status & TC)) && host->mrq)
omap_hsmmc_xfer_done(host, data);
-}
-
-/*
- * MMC controller IRQ handler
- */
-static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
-{
- struct omap_hsmmc_host *host = dev_id;
- int status;
- status = OMAP_HSMMC_READ(host->base, STAT);
- do {
- omap_hsmmc_do_irq(host, status);
- /* Flush posted write */
- status = OMAP_HSMMC_READ(host->base, STAT);
- } while (status & INT_EN_MASK);
+ spin_unlock(&host->irq_lock);
return IRQ_HANDLED;
}
@@ -1316,11 +1288,9 @@ static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host,
/*
* DMA call back function
*/
-static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
+static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data)
{
- struct omap_hsmmc_host *host = cb_data;
- struct mmc_data *data = host->mrq->data;
- int dma_ch, req_in_progress;
+ struct omap_hsmmc_host *host = data;
if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n",
@@ -1328,38 +1298,24 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
return;
}
- spin_lock(&host->irq_lock);
- if (host->dma_ch < 0) {
- spin_unlock(&host->irq_lock);
+ if (host->dma_ch < 0)
return;
- }
host->dma_sg_idx++;
if (host->dma_sg_idx < host->dma_len) {
/* Fire up the next transfer. */
- omap_hsmmc_config_dma_params(host, data,
- data->sg + host->dma_sg_idx);
- spin_unlock(&host->irq_lock);
+ omap_hsmmc_config_dma_params(host, host->data,
+ host->data->sg + host->dma_sg_idx);
return;
}
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
- omap_hsmmc_get_dma_dir(host, data));
-
- req_in_progress = host->req_in_progress;
- dma_ch = host->dma_ch;
+ omap_free_dma(host->dma_ch);
host->dma_ch = -1;
- spin_unlock(&host->irq_lock);
-
- omap_free_dma(dma_ch);
-
- /* If DMA has finished after TC, complete the request */
- if (!req_in_progress) {
- struct mmc_request *mrq = host->mrq;
-
- host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
- }
+ /*
+ * DMA Callback: run in interrupt context.
+ * mutex_unlock will throw a kernel warning if used.
+ */
+ up(&host->sem);
}
/*
@@ -1368,7 +1324,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
struct mmc_request *req)
{
- int dma_ch = 0, ret = 0, i;
+ int dma_ch = 0, ret = 0, err = 1, i;
struct mmc_data *data = req->data;
/* Sanity check: all the SG entries must be aligned by block size. */
@@ -1385,7 +1341,23 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
*/
return -EINVAL;
- BUG_ON(host->dma_ch != -1);
+ /*
+ * If for some reason the DMA transfer is still active,
+ * we wait for timeout period and free the dma
+ */
+ if (host->dma_ch != -1) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(100);
+ if (down_trylock(&host->sem)) {
+ omap_free_dma(host->dma_ch);
+ host->dma_ch = -1;
+ up(&host->sem);
+ return err;
+ }
+ } else {
+ if (down_trylock(&host->sem))
+ return err;
+ }
ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data),
"MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch);
@@ -1485,27 +1457,37 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
struct omap_hsmmc_host *host = mmc_priv(mmc);
int err;
- BUG_ON(host->req_in_progress);
- BUG_ON(host->dma_ch != -1);
- if (host->protect_card) {
- if (host->reqs_blocked < 3) {
- /*
- * Ensure the controller is left in a consistent
- * state by resetting the command and data state
- * machines.
- */
- omap_hsmmc_reset_controller_fsm(host, SRD);
- omap_hsmmc_reset_controller_fsm(host, SRC);
- host->reqs_blocked += 1;
- }
- req->cmd->error = -EBADF;
- if (req->data)
- req->data->error = -EBADF;
- req->cmd->retries = 0;
- mmc_request_done(mmc, req);
- return;
- } else if (host->reqs_blocked)
- host->reqs_blocked = 0;
+ /*
+ * Prevent races with the interrupt handler because of unexpected
+ * interrupts, but not if we are already in interrupt context i.e.
+ * retries.
+ */
+ if (!in_interrupt()) {
+ spin_lock_irqsave(&host->irq_lock, host->flags);
+ /*
+ * Protect the card from I/O if there is a possibility
+ * it can be removed.
+ */
+ if (host->protect_card) {
+ if (host->reqs_blocked < 3) {
+ /*
+ * Ensure the controller is left in a consistent
+ * state by resetting the command and data state
+ * machines.
+ */
+ omap_hsmmc_reset_controller_fsm(host, SRD);
+ omap_hsmmc_reset_controller_fsm(host, SRC);
+ host->reqs_blocked += 1;
+ }
+ req->cmd->error = -EBADF;
+ if (req->data)
+ req->data->error = -EBADF;
+ spin_unlock_irqrestore(&host->irq_lock, host->flags);
+ mmc_request_done(mmc, req);
+ return;
+ } else if (host->reqs_blocked)
+ host->reqs_blocked = 0;
+ }
WARN_ON(host->mrq != NULL);
host->mrq = req;
err = omap_hsmmc_prepare_data(host, req);
@@ -1514,6 +1496,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
if (req->data)
req->data->error = err;
host->mrq = NULL;
+ if (!in_interrupt())
+ spin_unlock_irqrestore(&host->irq_lock, host->flags);
mmc_request_done(mmc, req);
return;
}
@@ -2093,6 +2077,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
mmc->f_min = 400000;
mmc->f_max = 52000000;
+ sema_init(&host->sem, 1);
spin_lock_init(&host->irq_lock);
host->iclk = clk_get(&pdev->dev, "ick");
@@ -2235,7 +2220,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
pdata->resume = omap_hsmmc_resume_cdirq;
}
- omap_hsmmc_disable_irq(host);
+ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+ OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
mmc_host_lazy_disable(host->mmc);
@@ -2356,7 +2342,10 @@ static int omap_hsmmc_suspend(struct device *dev)
ret = mmc_suspend_host(host->mmc);
mmc_host_enable(host->mmc);
if (ret == 0) {
- omap_hsmmc_disable_irq(host);
+ OMAP_HSMMC_WRITE(host->base, ISE, 0);
+ OMAP_HSMMC_WRITE(host->base, IE, 0);
+
+
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
mmc_host_disable(host->mmc);
--
1.6.6.1
@@ -1,51 +0,0 @@
From 75d9413d575f724e1f7c006fdef374fb1c200346 Mon Sep 17 00:00:00 2001
From: David Vrabel <david.vrabel@csr.com>
Date: Fri, 2 Apr 2010 08:41:47 -0700
Subject: [PATCH 12/32] Don't turn SDIO cards off to save power. Doing so will lose all internal state in the card.
Signed-off-by: David Vrabel <david.vrabel@csr.com>
---
drivers/mmc/host/omap_hsmmc.c | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 15a023b..83f93ab 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -29,6 +29,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/core.h>
#include <linux/mmc/mmc.h>
+#include <linux/mmc/card.h>
#include <linux/io.h>
#include <linux/semaphore.h>
#include <linux/gpio.h>
@@ -1760,8 +1761,12 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host)
mmc_slot(host).card_detect ||
(mmc_slot(host).get_cover_state &&
mmc_slot(host).get_cover_state(host->dev, host->slot_id)))) {
- mmc_release_host(host->mmc);
- return 0;
+ goto out;
+ }
+
+ /* Don't turn SDIO cards off. */
+ if (host->mmc->card && mmc_card_sdio(host->mmc->card)) {
+ goto out;
}
mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
@@ -1772,9 +1777,8 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host)
host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
host->dpm_state = OFF;
-
+out:
mmc_release_host(host->mmc);
-
return 0;
}
--
1.6.6.1
@@ -1,288 +0,0 @@
From 948eeb1f03da5fca0f6734c10efbc35ad63a1d08 Mon Sep 17 00:00:00 2001
From: David Vrabel <david.vrabel@csr.com>
Date: Fri, 2 Apr 2010 08:42:22 -0700
Subject: [PATCH 13/32] Enable the use of SDIO card interrupts.
FCLK must be enabled while SDIO interrupts are enabled or the MMC
module won't wake-up (even though ENAWAKEUP in SYSCONFIG and IWE in
HTCL have been set). Enabling the MMC module to wake-up would require
configuring the MMC module (and the mmci_dat[1] GPIO when the CORE
power domain is OFF) as wake-up sources in the PRCM.
The writes to STAT and ISE when starting a command are unnecessary and
have been removed.
Signed-off-by: David Vrabel <david.vrabel@csr.com>
---
drivers/mmc/host/omap_hsmmc.c | 118 +++++++++++++++++++++++++++++------------
1 files changed, 83 insertions(+), 35 deletions(-)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 83f93ab..d57686c 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -67,6 +67,7 @@
#define SDVS_MASK 0x00000E00
#define SDVSCLR 0xFFFFF1FF
#define SDVSDET 0x00000400
+#define ENAWAKEUP (1 << 2)
#define AUTOIDLE 0x1
#define SDBP (1 << 8)
#define DTO 0xe
@@ -77,10 +78,13 @@
#define CLKD_SHIFT 6
#define DTO_MASK 0x000F0000
#define DTO_SHIFT 16
+#define CIRQ_ENABLE (1 << 8)
#define INT_EN_MASK 0x307F0033
#define BWR_ENABLE (1 << 4)
#define BRR_ENABLE (1 << 5)
#define DTO_ENABLE (1 << 20)
+#define CTPL (1 << 11)
+#define CLKEXTFREE (1 << 16)
#define INIT_STREAM (1 << 1)
#define DP_SELECT (1 << 21)
#define DDIR (1 << 4)
@@ -88,10 +92,12 @@
#define MSBS (1 << 5)
#define BCE (1 << 1)
#define FOUR_BIT (1 << 1)
+#define IWE (1 << 24)
#define DW8 (1 << 5)
#define CC 0x1
#define TC 0x02
#define OD 0x1
+#define CIRQ (1 << 8)
#define ERR (1 << 15)
#define CMD_TIMEOUT (1 << 16)
#define DATA_TIMEOUT (1 << 20)
@@ -186,6 +192,7 @@ struct omap_hsmmc_host {
int protect_card;
int reqs_blocked;
int use_reg;
+ int sdio_int;
struct omap_mmc_platform_data *pdata;
};
@@ -598,7 +605,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
;
OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
- OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
+ OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE | ENAWAKEUP);
if (host->id == OMAP_MMC1_DEVID) {
if (host->power_mode != MMC_POWER_OFF &&
@@ -613,7 +620,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
}
OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL) | hctl);
+ OMAP_HSMMC_READ(host->base, HCTL) | hctl | IWE);
OMAP_HSMMC_WRITE(host->base, CAPA,
OMAP_HSMMC_READ(host->base, CAPA) | capa);
@@ -627,7 +634,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
;
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
- OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK | CIRQ);
OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
/* Do not initialize card-specific things if the power is off */
@@ -791,22 +798,19 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
struct mmc_data *data)
{
int cmdreg = 0, resptype = 0, cmdtype = 0;
+ int int_en_mask = INT_EN_MASK;
dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
host->cmd = cmd;
- /*
- * Clear status bits and enable interrupts
- */
- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
- OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
-
if (host->use_dma)
- OMAP_HSMMC_WRITE(host->base, IE,
- INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
- else
- OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+ int_en_mask &= ~(BRR_ENABLE | BWR_ENABLE);
+
+ if (host->sdio_int)
+ int_en_mask |= CIRQ;
+
+ OMAP_HSMMC_WRITE(host->base, IE, int_en_mask);
host->response_busy = 0;
if (cmd->flags & MMC_RSP_PRESENT) {
@@ -1019,23 +1023,26 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
{
struct omap_hsmmc_host *host = dev_id;
struct mmc_data *data;
- int end_cmd = 0, end_trans = 0, status;
+ u32 status;
+ int end_cmd = 0, end_trans = 0;
+ bool card_irq = false;
spin_lock(&host->irq_lock);
- if (host->mrq == NULL) {
- OMAP_HSMMC_WRITE(host->base, STAT,
- OMAP_HSMMC_READ(host->base, STAT));
- /* Flush posted write */
- OMAP_HSMMC_READ(host->base, STAT);
- spin_unlock(&host->irq_lock);
- return IRQ_HANDLED;
- }
-
- data = host->data;
status = OMAP_HSMMC_READ(host->base, STAT);
+ OMAP_HSMMC_WRITE(host->base, STAT, status);
+ OMAP_HSMMC_READ(host->base, STAT); /* Flush posted write. */
+
dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
+ if (status & CIRQ)
+ card_irq = true;
+
+ if (host->mrq == NULL)
+ goto out;
+
+ data = host->data;
+
if (status & ERR) {
#ifdef CONFIG_MMC_DEBUG
omap_hsmmc_report_irq(host, status);
@@ -1085,17 +1092,16 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
}
}
- OMAP_HSMMC_WRITE(host->base, STAT, status);
- /* Flush posted write */
- OMAP_HSMMC_READ(host->base, STAT);
-
if (end_cmd || ((status & CC) && host->cmd))
omap_hsmmc_cmd_done(host, host->cmd);
if ((end_trans || (status & TC)) && host->mrq)
omap_hsmmc_xfer_done(host, data);
-
+out:
spin_unlock(&host->irq_lock);
+ if (card_irq)
+ mmc_signal_sdio_irq(host->mmc);
+
return IRQ_HANDLED;
}
@@ -1643,6 +1649,47 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
mmc_slot(host).init_card(card);
}
+static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct omap_hsmmc_host *host = mmc_priv(mmc);
+ u32 ie, con;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->irq_lock, flags);
+
+ /*
+ * When interrupts are enabled, CTPL must be set to enable
+ * DAT1 input buffer (or the card interrupt is always
+ * asserted) and FCLK must be enabled as wake-up does not
+ * work. Take care to disable FCLK after all the register
+ * accesses as they might not complete if FCLK is off.
+ *
+ * FIXME: if the MMC module (and the mmci_dat[1] GPIO when the
+ * CORE power domain is OFF) are configured as a wake-up
+ * sources in the PRCM, then FCLK could be switched off. This
+ * might add too much latency.
+ */
+ con = OMAP_HSMMC_READ(host->base, CON);
+ ie = OMAP_HSMMC_READ(host->base, IE);
+ if (enable) {
+ clk_enable(host->fclk);
+ ie |= CIRQ_ENABLE;
+ con |= CTPL | CLKEXTFREE;
+ host->sdio_int = 1;
+ } else {
+ ie &= ~CIRQ_ENABLE;
+ con &= ~(CTPL | CLKEXTFREE);
+ host->sdio_int = 0;
+ }
+ OMAP_HSMMC_WRITE(host->base, CON, con);
+ OMAP_HSMMC_WRITE(host->base, IE, ie);
+ OMAP_HSMMC_READ(host->base, IE); /* flush posted write */
+ if (!enable)
+ clk_disable(host->fclk);
+
+ spin_unlock_irqrestore(&host->irq_lock, flags);
+}
+
static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
{
u32 hctl, capa, value;
@@ -1657,14 +1704,14 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
}
value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
- OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
+ OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl | IWE);
value = OMAP_HSMMC_READ(host->base, CAPA);
OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
/* Set the controller to AUTO IDLE mode */
value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
- OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
+ OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE | ENAWAKEUP);
/* Set SD bus power bit */
set_sd_bus_power(host);
@@ -1918,7 +1965,7 @@ static const struct mmc_host_ops omap_hsmmc_ops = {
.get_cd = omap_hsmmc_get_cd,
.get_ro = omap_hsmmc_get_ro,
.init_card = omap_hsmmc_init_card,
- /* NYET -- enable_sdio_irq */
+ .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
};
static const struct mmc_host_ops omap_hsmmc_ps_ops = {
@@ -1929,7 +1976,7 @@ static const struct mmc_host_ops omap_hsmmc_ps_ops = {
.get_cd = omap_hsmmc_get_cd,
.get_ro = omap_hsmmc_get_ro,
.init_card = omap_hsmmc_init_card,
- /* NYET -- enable_sdio_irq */
+ .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
};
#ifdef CONFIG_DEBUG_FS
@@ -2145,7 +2192,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
mmc->max_seg_size = mmc->max_req_size;
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
- MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
+ MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE |
+ MMC_CAP_SDIO_IRQ;
mmc->caps |= mmc_slot(host).caps;
if (mmc->caps & MMC_CAP_8_BIT_DATA)
@@ -2224,7 +2272,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
pdata->resume = omap_hsmmc_resume_cdirq;
}
- OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+ OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK | CIRQ);
OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
mmc_host_lazy_disable(host->mmc);
--
1.6.6.1
@@ -1,27 +0,0 @@
From f646d3df7a7160fd80f20416c4a0fce55946f527 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Thu, 17 Dec 2009 12:45:20 -0800
Subject: [PATCH 14/32] soc: codecs: Enable audio capture by default for twl4030
---
sound/soc/codecs/twl4030.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 575238d..bd51f72 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -56,8 +56,8 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
0x00, /* REG_OPTION (0x2) */
0x00, /* REG_UNKNOWN (0x3) */
0x00, /* REG_MICBIAS_CTL (0x4) */
- 0x00, /* REG_ANAMICL (0x5) */
- 0x00, /* REG_ANAMICR (0x6) */
+ 0x34, /* REG_ANAMICL (0x5) */
+ 0x14, /* REG_ANAMICR (0x6) */
0x00, /* REG_AVADC_CTL (0x7) */
0x00, /* REG_ADCMICSEL (0x8) */
0x00, /* REG_DIGMIXING (0x9) */
--
1.6.6.1
@@ -1,25 +0,0 @@
From 00adf70cb5f8706ac5e7b1ec6f5a94f7e490b606 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Wed, 29 Dec 2010 11:39:16 -0800
Subject: [PATCH 15/32] soc: codecs: twl4030: Turn on mic bias by default
---
sound/soc/codecs/twl4030.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index bd51f72..8949773 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -55,7 +55,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
0x00, /* REG_CODEC_MODE (0x1) */
0x00, /* REG_OPTION (0x2) */
0x00, /* REG_UNKNOWN (0x3) */
- 0x00, /* REG_MICBIAS_CTL (0x4) */
+ 0x03, /* REG_MICBIAS_CTL (0x4) */
0x34, /* REG_ANAMICL (0x5) */
0x14, /* REG_ANAMICR (0x6) */
0x00, /* REG_AVADC_CTL (0x7) */
--
1.6.6.1
@@ -1,55 +0,0 @@
From 6f432e1e39f276a41d600d1cc9cd17fc088877d8 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Thu, 4 Feb 2010 12:26:22 -0800
Subject: [PATCH 16/32] RTC: add support for backup battery recharge
---
drivers/rtc/rtc-twl.c | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index f9a2799..713b8ea 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -30,6 +30,23 @@
#include <linux/i2c/twl.h>
+/*
+ * PM_RECEIVER block register offsets (use TWL4030_MODULE_PM_RECEIVER)
+ */
+#define REG_BB_CFG 0x12
+
+/* PM_RECEIVER BB_CFG bitfields */
+#define BIT_PM_RECEIVER_BB_CFG_BBCHEN 0x10
+#define BIT_PM_RECEIVER_BB_CFG_BBSEL 0x0C
+#define BIT_PM_RECEIVER_BB_CFG_BBSEL_2V5 0x00
+#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3V0 0x04
+#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3V1 0x08
+#define BIT_PM_RECEIVER_BB_CFG_BBSEL_3v2 0x0c
+#define BIT_PM_RECEIVER_BB_CFG_BBISEL 0x03
+#define BIT_PM_RECEIVER_BB_CFG_BBISEL_25UA 0x00
+#define BIT_PM_RECEIVER_BB_CFG_BBISEL_150UA 0x01
+#define BIT_PM_RECEIVER_BB_CFG_BBISEL_500UA 0x02
+#define BIT_PM_RECEIVER_BB_CFG_BBISEL_1MA 0x03
/*
* RTC block register offsets (use TWL_MODULE_RTC)
@@ -495,6 +512,14 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
if (ret < 0)
goto out2;
+ /* enable backup battery charging */
+ /* use a conservative 25uA @ 3.1V */
+ ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+ BIT_PM_RECEIVER_BB_CFG_BBCHEN |
+ BIT_PM_RECEIVER_BB_CFG_BBSEL_3V1 |
+ BIT_PM_RECEIVER_BB_CFG_BBISEL_25UA,
+ REG_BB_CFG);
+
return ret;
out2:
--
1.6.6.1
@@ -1,39 +0,0 @@
From 56dc96df8ff5e3db6afde96d64d74200f85e59c2 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Sun, 24 Jan 2010 09:33:56 -0800
Subject: [PATCH 17/32] ARM: OMAP2: mmc-twl4030: move clock input selection prior to vcc test
otherwise it is not executed on systems that use non-twl regulators
---
arch/arm/mach-omap2/hsmmc.c | 14 ++++++--------
1 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index b2f30be..84d5ef6 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -185,15 +185,13 @@ static void hsmmc23_before_set_reg(struct device *dev, int slot,
if (mmc->slots[0].remux)
mmc->slots[0].remux(dev, slot, power_on);
- if (power_on) {
- /* Only MMC2 supports a CLKIN */
- if (mmc->slots[0].internal_clock) {
- u32 reg;
+ /* Only MMC2 supports a CLKIN */
+ if (mmc->slots[0].internal_clock) {
+ u32 reg;
- reg = omap_ctrl_readl(control_devconf1_offset);
- reg |= OMAP2_MMCSDIO2ADPCLKISEL;
- omap_ctrl_writel(reg, control_devconf1_offset);
- }
+ reg = omap_ctrl_readl(control_devconf1_offset);
+ reg |= OMAP2_MMCSDIO2ADPCLKISEL;
+ omap_ctrl_writel(reg, control_devconf1_offset);
}
}
--
1.6.6.1
@@ -1,103 +0,0 @@
From 8c257a6e7460ceb8c899980f7dad701ceb619adc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bernhard=20W=C3=B6rndl-Aichriedler?= <bwa@xdevelop.at>
Date: Sat, 15 May 2010 16:34:05 +0200
Subject: [PATCH 18/32] Add power-off support for the TWL4030 companion
This patch adds support for the power-off on shutdown feature of the TWL4030
---
drivers/mfd/Kconfig | 6 ++++++
drivers/mfd/twl-core.c | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+), 0 deletions(-)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3ed3ff0..fe2370a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -210,6 +210,12 @@ config TWL4030_CODEC
select MFD_CORE
default n
+config TWL4030_POWEROFF
+ bool "TWL4030 Allow power-off on shutdown"
+ depends on TWL4030_CORE
+ help
+ Enables the CPU to power-off the system on shutdown
+
config TWL6030_PWM
tristate "TWL6030 PWM (Pulse Width Modulator) Support"
depends on TWL4030_CORE
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 960b5be..8804550 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -122,6 +122,12 @@
#define twl_has_bci() false
#endif
+#if defined (CONFIG_TWL4030_POWEROFF)
+#define twl_has_poweroff() true
+#else
+#define twl_has_poweroff() false
+#endif
+
/* Triton Core internal information (BEGIN) */
/* Last - for index max*/
@@ -224,6 +230,10 @@
#define TWL5031 BIT(2) /* twl5031 has different registers */
#define TWL6030_CLASS BIT(3) /* TWL6030 class */
+/* for pm_power_off */
+#define PWR_P1_SW_EVENTS 0x10
+#define PWR_DEVOFF (1 << 0)
+
/*----------------------------------------------------------------------*/
/* is driver active, bound to a chip? */
@@ -1006,6 +1016,30 @@ static int twl_remove(struct i2c_client *client)
return 0;
}
+static void twl_poweroff(void)
+{
+ int err;
+ u8 val;
+
+ err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
+ PWR_P1_SW_EVENTS);
+ if (err) {
+ pr_err("%s: i2c error %d while reading TWL4030"
+ "PM_MASTER P1_SW_EVENTS\n",
+ DRIVER_NAME, err);
+ return;
+ }
+
+ val |= PWR_DEVOFF;
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
+ PWR_P1_SW_EVENTS);
+ if (err)
+ pr_err("%s: i2c error %d while writing TWL4030"
+ "PM_MASTER P1_SW_EVENTS\n",
+ DRIVER_NAME, err);
+}
+
/* NOTE: this driver only handles a single twl4030/tps659x0 chip */
static int __devinit
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
@@ -1093,6 +1127,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}
+ if(twl_has_poweroff())
+ {
+ /* initialize pm_power_off routine */
+ pm_power_off = twl_poweroff;
+ }
+
status = add_children(pdata, id->driver_data);
fail:
if (status < 0)
--
1.6.6.1
@@ -1,33 +0,0 @@
From 46ea520a3c80914ae5ad3e35be7b8650706da3e6 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Thu, 17 Dec 2009 14:27:15 -0800
Subject: [PATCH 19/32] ARM: OMAP: Add twl4030 madc support to Overo
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
arch/arm/mach-omap2/board-overo.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 59ca333..86f76e9 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -637,10 +637,15 @@ static struct twl4030_codec_data overo_codec_data = {
.audio = &overo_audio_data,
};
+static struct twl4030_madc_platform_data overo_madc_data = {
+ .irq_line = 1,
+};
+
static struct twl4030_platform_data overo_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
.gpio = &overo_gpio_data,
+ .madc = &overo_madc_data,
.usb = &overo_usb_data,
.codec = &overo_codec_data,
.vmmc1 = &overo_vmmc1,
--
1.6.6.1
@@ -1,46 +0,0 @@
From 931bd787effbd6f1f00468c89c647c66c0bbc164 Mon Sep 17 00:00:00 2001
From: Keerthy <j-keerthy@ti.com>
Date: Wed, 4 May 2011 01:14:50 +0530
Subject: [PATCH 20/32] Enabling Hwmon driver for twl4030-madc
Signed-off-by: Keerthy <j-keerthy@ti.com>
---
drivers/mfd/twl-core.c | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 8804550..d9435e4 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -83,6 +83,13 @@
#define twl_has_madc() false
#endif
+#if defined(CONFIG_SENSORS_TWL4030_MADC) ||\
+ defined(CONFIG_SENSORS_TWL4030_MADC_MODULE)
+#define twl_has_madc_hwmon() true
+#else
+#define twl_has_madc_hwmon() false
+#endif
+
#ifdef CONFIG_TWL4030_POWER
#define twl_has_power() true
#else
@@ -619,6 +626,14 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
return PTR_ERR(child);
}
+if (twl_has_madc_hwmon()) {
+ child = add_child(2, "twl4030_madc_hwmon",
+ NULL, 0,
+ true, pdata->irq_base + MADC_INTR_OFFSET, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
if (twl_has_rtc()) {
/*
* REVISIT platform_data here currently might expose the
--
1.6.6.1
@@ -1,54 +0,0 @@
From aee147073ad84a7c81fba36dd475c6d2d17ed728 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Sat, 23 Jan 2010 06:26:54 -0800
Subject: [PATCH 21/32] mfd: twl-core: enable madc clock
Now that the madc driver has been merged it is also necessary to enable the clock to the madc block
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
drivers/mfd/twl-core.c | 8 ++++++++
include/linux/i2c/twl.h | 1 +
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index d9435e4..9096d7d 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -222,6 +222,11 @@
/* Few power values */
#define R_CFG_BOOT 0x05
+#define R_GPBR1 0x0C
+
+/* MADC clock values for R_GPBR1 */
+#define MADC_HFCLK_EN 0x80
+#define DEFAULT_MADC_CLK_EN 0x10
/* some fields in R_CFG_BOOT */
#define HFCLK_FREQ_19p2_MHZ (1 << 0)
@@ -992,6 +997,9 @@ static void clocks_init(struct device *dev,
e |= unprotect_pm_master();
/* effect->MADC+USB ck en */
+ if (twl_has_madc())
+ e |= twl_i2c_write_u8(TWL_MODULE_INTBR,
+ MADC_HFCLK_EN | DEFAULT_MADC_CLK_EN, R_GPBR1);
e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
e |= protect_pm_master();
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h
index 0c0d1ae..cbbf3b3 100644
--- a/include/linux/i2c/twl.h
+++ b/include/linux/i2c/twl.h
@@ -74,6 +74,7 @@
#define TWL_MODULE_USB TWL4030_MODULE_USB
#define TWL_MODULE_AUDIO_VOICE TWL4030_MODULE_AUDIO_VOICE
+#define TWL_MODULE_INTBR TWL4030_MODULE_INTBR
#define TWL_MODULE_PIH TWL4030_MODULE_PIH
#define TWL_MODULE_MADC TWL4030_MODULE_MADC
#define TWL_MODULE_MAIN_CHARGE TWL4030_MODULE_MAIN_CHARGE
--
1.6.6.1
@@ -1,25 +0,0 @@
From 29dd1b5655f60f97a9cee2f4ff1d27d7da1329a1 Mon Sep 17 00:00:00 2001
From: Ilkka Koskinen <ilkka.koskinen@nokia.com>
Date: Wed, 16 Mar 2011 16:07:14 +0000
Subject: [PATCH 22/32] rtc-twl: Switch to using threaded irq
---
drivers/rtc/rtc-twl.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index 713b8ea..1fe1bc9 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -479,7 +479,7 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
if (ret < 0)
goto out1;
- ret = request_irq(irq, twl_rtc_interrupt,
+ ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt,
IRQF_TRIGGER_RISING,
dev_name(&rtc->dev), rtc);
if (ret < 0) {
--
1.6.6.1
@@ -1,49 +0,0 @@
From 92c06791d4d6b537a9a83b27d71d7d3dd348f93f Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Wed, 24 Feb 2010 10:37:22 -0800
Subject: [PATCH 23/32] ARM: OMAP: automatically set musb mode in platform data based on CONFIG options
---
arch/arm/mach-omap2/board-omap3beagle.c | 6 ++++++
arch/arm/mach-omap2/board-overo.c | 6 ++++++
2 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 33007fd..2de4b02 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -604,7 +604,13 @@ static struct omap_board_mux board_mux[] __initdata = {
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_ULPI,
+#if defined(CONFIG_USB_MUSB_OTG)
.mode = MUSB_OTG,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+ .mode = MUSB_PERIPHERAL,
+#else
+ .mode = MUSB_HOST,
+#endif
.power = 100,
};
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 86f76e9..61c59fc 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -729,7 +729,13 @@ static struct omap_board_mux board_mux[] __initdata = {
static struct omap_musb_board_data musb_board_data = {
.interface_type = MUSB_INTERFACE_ULPI,
+#if defined(CONFIG_USB_MUSB_OTG)
.mode = MUSB_OTG,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+ .mode = MUSB_PERIPHERAL,
+#else
+ .mode = MUSB_HOST,
+#endif
.power = 100,
};
--
1.6.6.1
@@ -1,28 +0,0 @@
From a442a2b9b2f9f51375f8a796ee88784d3754be00 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Wed, 12 Jan 2011 05:54:55 -0800
Subject: [PATCH 24/32] omap: mmc: Adjust dto to eliminate timeout errors
A number of SD card types were experiencing timeout errors. This
could also lead to data corruption in some cases.
This fix proposed by Sukumar Ghoral of TI.
---
drivers/mmc/host/omap_hsmmc.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index d57686c..7fb03e8 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1400,6 +1400,7 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
timeout = timeout_ns / cycle_ns;
timeout += timeout_clks;
+ timeout *= 2;
if (timeout) {
while ((timeout & 0x80000000) == 0) {
dto += 1;
--
1.6.6.1
@@ -1,95 +0,0 @@
From acf75c8b4d0f6775527636bf9d41bb1f74fc2f97 Mon Sep 17 00:00:00 2001
From: Charles Manning <cdhmanning@gmail.com>
Date: Tue, 18 Jan 2011 11:25:25 +1300
Subject: [PATCH 25/32] omap: Fix mtd subpage read alignment
This allows the omap2 prefetch engine to work properly for subpage
reads. Without this ECC errors will stop UBIFS from working.
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
---
drivers/mtd/nand/nand_base.c | 19 +++++++++++++++++++
drivers/mtd/nand/omap2.c | 1 +
include/linux/mtd/nand.h | 3 +++
3 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index c54a4cb..6ca7098 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1157,6 +1157,22 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
+ * nand_align_subpage32 - function to align subpage read to 32-bits
+ * @mtd: mtd info structure
+ * @buf: pointer to offset that needs to be aligned
+ * @len: pointer to length that needs to be aligned.
+ */
+
+void nand_align_subpage32(int *offs, int *len)
+{
+ int diff = *offs & 3;
+
+ *offs = *offs - diff;
+ *len = (*len + diff + 3) & ~3;
+}
+EXPORT_SYMBOL(nand_align_subpage32);
+
+/**
* nand_read_subpage - [REPLACABLE] software ecc based sub-page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
@@ -1221,6 +1237,9 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
aligned_len++;
+ if(chip->align_subpage)
+ chip->align_subpage(&aligned_pos, &aligned_len);
+
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
mtd->writesize + aligned_pos, -1);
chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index da9a351..bb89c65 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1069,6 +1069,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->nand.ecc.correct = omap_correct_data;
info->nand.ecc.mode = NAND_ECC_HW;
}
+ info->nand.align_subpage = nand_align_subpage32;
/* DIP switches on some boards change between 8 and 16 bit
* bus widths for flash. Try the other width if the first try fails.
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index d441927..311f211 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -479,6 +479,7 @@ struct nand_buffers {
* additional error status checks (determine if errors are
* correctable).
* @write_page: [REPLACEABLE] High-level page write function
+ * @align_subpage: [OPTIONAL] Aligns subpage read buffer.
*/
struct nand_chip {
@@ -507,6 +508,7 @@ struct nand_chip {
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int page, int cached, int raw);
+ void (*align_subpage)(int *offs, int *len);
int chip_delay;
unsigned int options;
@@ -602,6 +604,7 @@ extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt);
extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf);
+extern void nand_align_subpage32(int *offs, int *len);
/**
* struct platform_nand_chip - chip level device structure
--
1.6.6.1
@@ -1,35 +0,0 @@
From 048c2b85c12ac4aa8cd82201e1ade332557e4380 Mon Sep 17 00:00:00 2001
From: Charles Manning <manningc2@actrix.gen.nz>
Date: Thu, 16 Dec 2010 20:35:56 -0800
Subject: [PATCH 26/32] mtd: nand: omap2: Force all buffer reads to u32 alignment
---
drivers/mtd/nand/omap2.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index bb89c65..832f111 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -247,6 +247,18 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
int ret = 0;
u32 *p = (u32 *)buf;
+ /* u32 align the buffer and read */
+ /* NB: This assumes the buf ptr can be aligned *down* which is a valid.
+ * Assumption when dealing with ecc buffers etc.
+ */
+ u32 addr = (u32)p;
+
+ int diff = addr & 3;
+ addr -= diff;
+ len += diff;
+ len = (len + 3) & ~3;
+ p = (u32 *)addr;
+
/* take care of subpage reads */
if (len % 4) {
if (info->nand.options & NAND_BUSWIDTH_16)
--
1.6.6.1
@@ -1,63 +0,0 @@
From fb4dfff6a6e107e0e526801e7add4a9aaeab1eab Mon Sep 17 00:00:00 2001
From: kishore kadiyala <kishore.kadiyala@ti.com>
Date: Mon, 2 May 2011 11:10:38 +0000
Subject: [PATCH 27/32] omap : nand : fix subpage ecc issue with prefetch
For prefetch engine, read and write got broken in commit '2c01946c'.
We never hit a scenario of not getting 'gpmc_prefetch_enable'
call success.
When reading/writing a subpage with a non divisible by 4 ecc number
of bytes, the mis-aligned bytes gets handled first before enabling
the Prefetch engine, then it reads/writes rest of the bytes.
Signed-off-by: Kishore Kadiyala <kishore.kadiyala@ti.com>
Signed-off-by: Vimal Singh <vimal.newwork@gmail.com>
Reported-by: Bryan DE FARIA <bdefaria@adeneo-embedded.com>
---
drivers/mtd/nand/omap2.c | 12 +++++-------
1 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 832f111..471a39b 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -275,11 +275,10 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
if (ret) {
/* PFPW engine is busy, use cpu copy method */
if (info->nand.options & NAND_BUSWIDTH_16)
- omap_read_buf16(mtd, buf, len);
+ omap_read_buf16(mtd, (u_char *)p, len);
else
- omap_read_buf8(mtd, buf, len);
+ omap_read_buf8(mtd, (u_char *)p, len);
} else {
- p = (u32 *) buf;
do {
r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
r_count = r_count >> 2;
@@ -305,7 +304,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
struct omap_nand_info, mtd);
uint32_t w_count = 0;
int i = 0, ret = 0;
- u16 *p;
+ u16 *p = (u16 *)buf;
unsigned long tim, limit;
/* take care of subpage writes */
@@ -321,11 +320,10 @@ static void omap_write_buf_pref(struct mtd_info *mtd,
if (ret) {
/* PFPW engine is busy, use cpu copy method */
if (info->nand.options & NAND_BUSWIDTH_16)
- omap_write_buf16(mtd, buf, len);
+ omap_write_buf16(mtd, (u_char *)p, len);
else
- omap_write_buf8(mtd, buf, len);
+ omap_write_buf8(mtd, (u_char *)p, len);
} else {
- p = (u16 *) buf;
while (len) {
w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT);
w_count = w_count >> 1;
--
1.6.6.1
@@ -1,46 +0,0 @@
From ee2dcb39e9255fc0aa6b4e267e9553bdbd11e82b Mon Sep 17 00:00:00 2001
From: Scott Ellis <scottellis.developer@gmail.com>
Date: Sun, 23 Jan 2011 20:39:35 -0800
Subject: [PATCH 28/32] OMAP: Overo: Add support for spidev
---
arch/arm/mach-omap2/board-overo.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 61c59fc..05dd3eb 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -683,6 +683,14 @@ static struct spi_board_info overo_spi_board_info[] __initdata = {
.irq = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
.platform_data = &ads7846_config,
},
+#elif defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+ {
+ .modalias = "spidev",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 48000000,
+ .mode = SPI_MODE_0,
+ },
#endif
#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
@@ -693,6 +701,14 @@ static struct spi_board_info overo_spi_board_info[] __initdata = {
.max_speed_hz = 500000,
.mode = SPI_MODE_3,
},
+#elif defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+ {
+ .modalias = "spidev",
+ .bus_num = 1,
+ .chip_select = 1,
+ .max_speed_hz = 48000000,
+ .mode = SPI_MODE_0,
+ },
#endif
};
--
1.6.6.1
@@ -1,34 +0,0 @@
From 728b784863056a2b2e35134f71082271ebab0892 Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Mon, 23 May 2011 12:16:50 -0700
Subject: [PATCH 30/32] omap: Change omap_device activate latency messages from pr_warning to pr_debug
Messages can be safely ignored, so reduce console noise
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
arch/arm/plat-omap/omap_device.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 9bbda9a..ca8a479 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -145,12 +145,12 @@ static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
odpl->activate_lat_worst = act_lat;
if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
odpl->activate_lat = act_lat;
- pr_warning("omap_device: %s.%d: new worst case "
+ pr_debug("omap_device: %s.%d: new worst case "
"activate latency %d: %llu\n",
od->pdev.name, od->pdev.id,
od->pm_lat_level, act_lat);
} else
- pr_warning("omap_device: %s.%d: activate "
+ pr_debug("omap_device: %s.%d: activate "
"latency %d higher than exptected. "
"(%llu > %d)\n",
od->pdev.name, od->pdev.id,
--
1.6.6.1
@@ -1,105 +0,0 @@
From 530abfee962141f263344b4de3ca48b57e5e514c Mon Sep 17 00:00:00 2001
From: Steve Sakoman <steve@sakoman.com>
Date: Tue, 24 May 2011 20:36:07 -0700
Subject: [PATCH 31/32] omap: overo: Add opp init
omap: overo: Add opp init
Work in progress
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
arch/arm/mach-omap2/board-overo.c | 49 +++++++++++++++++++++++++++++++++++++
1 files changed, 49 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 05dd3eb..8c2d21f 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/opp.h>
#include <linux/platform_device.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
@@ -43,6 +44,7 @@
#include <plat/board.h>
#include <plat/common.h>
+#include <plat/omap_device.h>
#include <plat/display.h>
#include <plat/panel-generic-dpi.h>
#include <mach/gpio.h>
@@ -54,6 +56,7 @@
#include <plat/usb.h>
#include "mux.h"
+#include "pm.h"
#include "sdram-micron-mt46h32m32lf-6.h"
#include "hsmmc.h"
@@ -755,6 +758,51 @@ static struct omap_musb_board_data musb_board_data = {
.power = 100,
};
+static void __init overo_opp_init(void)
+{
+ int r = 0;
+
+ /* Initialize the omap3 opp table */
+ if (omap3_opp_init()) {
+ pr_err("%s: opp default init failed\n", __func__);
+ return;
+ }
+
+ /* Custom OPP enabled for 36/3730 */
+ if (cpu_is_omap3630()) {
+ struct omap_hwmod *mh = omap_hwmod_lookup("mpu");
+ struct omap_hwmod *dh = omap_hwmod_lookup("iva");
+ struct device *dev;
+
+ if (!mh || !dh) {
+ pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n",
+ __func__, mh, dh);
+ return;
+ }
+ /* Enable MPU 1GHz and lower opps */
+ dev = &mh->od->pdev.dev;
+ r = opp_enable(dev, 1000000000);
+
+ /* Enable IVA 800MHz and lower opps */
+ dev = &dh->od->pdev.dev;
+ r |= opp_enable(dev, 800000000);
+
+ if (r) {
+ pr_err("%s: failed to enable higher opp %d\n",
+ __func__, r);
+ /*
+ * Cleanup - disable the higher freqs - we dont care
+ * about the results
+ */
+ dev = &mh->od->pdev.dev;
+ opp_disable(dev, 1000000000);
+ dev = &dh->od->pdev.dev;
+ opp_disable(dev, 800000000);
+ }
+ }
+ return;
+}
+
static void __init overo_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
@@ -770,6 +818,7 @@ static void __init overo_init(void)
overo_display_init();
overo_init_led();
overo_init_keys();
+ overo_opp_init();
/* Ensure SDRC pins are mux'd for self-refresh */
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
--
1.6.6.1
@@ -1,202 +0,0 @@
From cd9682b39f41675c4e551c607425226b38fab17d Mon Sep 17 00:00:00 2001
From: Sanjeev Premi <premi@ti.com>
Date: Tue, 18 Jan 2011 13:19:55 +0530
Subject: [PATCH 32/32] omap3: Add basic support for 720MHz part
This patch adds support for new speed enhanced parts with ARM
and IVA running at 720MHz and 520MHz respectively. These parts
can be probed at run-time by reading PRODID.SKUID[3:0] at
0x4830A20C [1].
This patch specifically does following:
* Detect devices capable of 720MHz.
* Add new OPP
* Ensure that OPP is conditionally enabled.
* Check for presence of IVA before attempting to enable
the corresponding OPP.
[1] http://focus.ti.com/lit/ug/spruff1d/spruff1d.pdf
Signed-off-by: Sanjeev Premi <premi@ti.com>
---
arch/arm/mach-omap2/control.h | 7 ++++
arch/arm/mach-omap2/id.c | 10 +++++
arch/arm/mach-omap2/opp3xxx_data.c | 63 ++++++++++++++++++++++++++++++++-
arch/arm/plat-omap/include/plat/cpu.h | 2 +
4 files changed, 81 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index c2804c1..6edd7cc 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -371,6 +371,13 @@
#define FEAT_NEON 0
#define FEAT_NEON_NONE 1
+/*
+ * Product ID register
+ */
+#define OMAP3_PRODID 0x020C
+
+#define OMAP3_SKUID_MASK 0x0f
+#define OMAP3_SKUID_720MHZ 0x08
#ifndef __ASSEMBLY__
#ifdef CONFIG_ARCH_OMAP2PLUS
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 2537090..b6ed78a 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -210,6 +210,15 @@ static void __init omap3_check_features(void)
* TODO: Get additional info (where applicable)
* e.g. Size of L2 cache.
*/
+
+ /*
+ * Does it support 720MHz?
+ */
+ status = (OMAP3_SKUID_MASK & read_tap_reg(OMAP3_PRODID));
+
+ if (status & OMAP3_SKUID_720MHZ) {
+ omap3_features |= OMAP3_HAS_720MHZ;
+ }
}
static void __init ti816x_check_features(void)
@@ -490,6 +499,7 @@ static void __init omap3_cpuinfo(void)
OMAP3_SHOW_FEATURE(neon);
OMAP3_SHOW_FEATURE(isp);
OMAP3_SHOW_FEATURE(192mhz_clk);
+ OMAP3_SHOW_FEATURE(720mhz);
printk(")\n");
}
diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c
index d95f3f9..44fbc84 100644
--- a/arch/arm/mach-omap2/opp3xxx_data.c
+++ b/arch/arm/mach-omap2/opp3xxx_data.c
@@ -18,8 +18,10 @@
* GNU General Public License for more details.
*/
#include <linux/module.h>
+#include <linux/opp.h>
#include <plat/cpu.h>
+#include <plat/omap_device.h>
#include "control.h"
#include "omap_opp_data.h"
@@ -98,6 +100,8 @@ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
OPP_INITIALIZER("mpu", true, 550000000, OMAP3430_VDD_MPU_OPP4_UV),
/* MPU OPP5 */
OPP_INITIALIZER("mpu", true, 600000000, OMAP3430_VDD_MPU_OPP5_UV),
+ /* MPU OPP6 */
+ OPP_INITIALIZER("mpu", false, 720000000, 1350000),
/*
* L3 OPP1 - 41.5 MHz is disabled because: The voltage for that OPP is
@@ -123,6 +127,8 @@ static struct omap_opp_def __initdata omap34xx_opp_def_list[] = {
OPP_INITIALIZER("iva", true, 400000000, OMAP3430_VDD_MPU_OPP4_UV),
/* DSP OPP5 */
OPP_INITIALIZER("iva", true, 430000000, OMAP3430_VDD_MPU_OPP5_UV),
+ /* DSP OPP6 */
+ OPP_INITIALIZER("iva", false, 520000000, 1350000),
};
static struct omap_opp_def __initdata omap36xx_opp_def_list[] = {
@@ -150,6 +156,57 @@ static struct omap_opp_def __initdata omap36xx_opp_def_list[] = {
OPP_INITIALIZER("iva", false, 800000000, OMAP3630_VDD_MPU_OPP1G_UV),
};
+
+/**
+ * omap3_opp_enable_720Mhz() - Enable the OPP corresponding to 720MHz
+ *
+ * This function would be executed only if the silicon is capable of
+ * running at the 720MHz.
+ */
+static int __init omap3_opp_enable_720Mhz(void)
+{
+ int r = -ENODEV;
+ struct omap_hwmod *oh_mpu = omap_hwmod_lookup("mpu");
+ struct omap_hwmod *oh_iva;
+ struct platform_device *pdev;
+
+ if (!oh_mpu || !oh_mpu->od) {
+ goto err;
+ } else {
+ pdev = &oh_mpu->od->pdev;
+
+ r = opp_enable(&pdev->dev, 720000000);
+ if (r < 0) {
+ dev_err(&pdev->dev,
+ "opp_enable() failed for mpu@720MHz");
+ goto err;
+ }
+ }
+
+ if (omap3_has_iva()) {
+ oh_iva = omap_hwmod_lookup("iva");
+
+ if (!oh_iva || !oh_iva->od) {
+ r = -ENODEV;
+ goto err;
+ } else {
+ pdev = &oh_iva->od->pdev;
+
+ r = opp_enable(&pdev->dev, 520000000);
+ if (r < 0) {
+ dev_err(&pdev->dev,
+ "opp_enable() failed for iva@520MHz");
+ goto err;
+ }
+ }
+ }
+
+ dev_info(&pdev->dev, "Enabled OPP corresponding to 720MHz\n");
+
+err:
+ return r;
+}
+
/**
* omap3_opp_init() - initialize omap3 opp table
*/
@@ -163,10 +220,14 @@ int __init omap3_opp_init(void)
if (cpu_is_omap3630())
r = omap_init_opp_table(omap36xx_opp_def_list,
ARRAY_SIZE(omap36xx_opp_def_list));
- else
+ else {
r = omap_init_opp_table(omap34xx_opp_def_list,
ARRAY_SIZE(omap34xx_opp_def_list));
+ if (omap3_has_720mhz())
+ r = omap3_opp_enable_720Mhz();
+ }
+
return r;
}
device_initcall(omap3_opp_init);
diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
index 8198bb6..5204c1e 100644
--- a/arch/arm/plat-omap/include/plat/cpu.h
+++ b/arch/arm/plat-omap/include/plat/cpu.h
@@ -478,6 +478,7 @@ extern u32 omap3_features;
#define OMAP3_HAS_192MHZ_CLK BIT(5)
#define OMAP3_HAS_IO_WAKEUP BIT(6)
#define OMAP3_HAS_SDRC BIT(7)
+#define OMAP3_HAS_720MHZ BIT(8)
#define OMAP3_HAS_FEATURE(feat,flag) \
static inline unsigned int omap3_has_ ##feat(void) \
@@ -493,5 +494,6 @@ OMAP3_HAS_FEATURE(isp, ISP)
OMAP3_HAS_FEATURE(192mhz_clk, 192MHZ_CLK)
OMAP3_HAS_FEATURE(io_wakeup, IO_WAKEUP)
OMAP3_HAS_FEATURE(sdrc, SDRC)
+OMAP3_HAS_FEATURE(720mhz, 720MHZ)
#endif
--
1.6.6.1
-123
View File
@@ -1,123 +0,0 @@
require linux.inc
DESCRIPTION = "Linux kernel for OMAP processors"
COMPATIBLE_MACHINE = "(beagleboard)"
# The main PR is now using MACHINE_KERNEL_PR, for omap3 see conf/machine/include/omap3.inc
SRCREV_pn-${PN} = "v2.6.39"
MACHINE_KERNEL_PR_append = "o"
FILESEXTRAPATHS_prepend := "{THISDIR}/${PN}-${PV}:"
SRC_URI += "git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git;protocol=git \
file://defconfig"
SRC_URI_append = " \
file://sakoman/0001-OMAP-DSS2-DSI-fix-use_sys_clk-highfreq.patch \
file://sakoman/0002-OMAP-DSS2-DSI-fix-dsi_dump_clocks.patch \
file://sakoman/0003-OMAP2PLUS-DSS2-Fix-Return-correct-lcd-clock-source-f.patch \
file://sakoman/0004-OMAP-DSS-DSI-Fix-DSI-PLL-power-bug.patch \
file://sakoman/0005-OMAP-DSS2-fix-panel-Kconfig-dependencies.patch \
file://sakoman/0006-OMAP-DSS2-add-bootarg-for-selecting-svideo-or-compos.patch \
file://sakoman/0007-video-add-timings-for-hd720.patch \
file://sakoman/0008-drivers-net-smsc911x-return-ENODEV-if-device-is-not-.patch \
file://sakoman/0009-drivers-input-touchscreen-ads7846-return-ENODEV-if-d.patch \
file://sakoman/0010-Revert-omap2_mcspi-Flush-posted-writes.patch \
file://sakoman/0011-Revert-omap_hsmmc-improve-interrupt-synchronisation.patch \
file://sakoman/0012-Don-t-turn-SDIO-cards-off-to-save-power.-Doing-so-wi.patch \
file://sakoman/0014-soc-codecs-Enable-audio-capture-by-default-for-twl40.patch \
file://sakoman/0015-soc-codecs-twl4030-Turn-on-mic-bias-by-default.patch \
file://sakoman/0016-RTC-add-support-for-backup-battery-recharge.patch \
file://sakoman/0017-ARM-OMAP2-mmc-twl4030-move-clock-input-selection-pri.patch \
file://sakoman/0018-Add-power-off-support-for-the-TWL4030-companion.patch \
file://sakoman/0019-ARM-OMAP-Add-twl4030-madc-support-to-Overo.patch \
file://sakoman/0020-Enabling-Hwmon-driver-for-twl4030-madc.patch \
file://sakoman/0021-mfd-twl-core-enable-madc-clock.patch \
file://sakoman/0022-rtc-twl-Switch-to-using-threaded-irq.patch \
file://sakoman/0023-ARM-OMAP-automatically-set-musb-mode-in-platform-dat.patch \
file://sakoman/0024-omap-mmc-Adjust-dto-to-eliminate-timeout-errors.patch \
file://sakoman/0025-omap-Fix-mtd-subpage-read-alignment.patch \
file://sakoman/0026-mtd-nand-omap2-Force-all-buffer-reads-to-u32-alignme.patch \
file://sakoman/0027-omap-nand-fix-subpage-ecc-issue-with-prefetch.patch \
file://sakoman/0028-OMAP-Overo-Add-support-for-spidev.patch \
file://sakoman/0029-unionfs-Add-support-for-unionfs-2.5.9.patch \
file://sakoman/0030-omap-Change-omap_device-activate-latency-messages-fr.patch \
file://sakoman/0031-omap-overo-Add-opp-init.patch \
file://sakoman/0032-omap3-Add-basic-support-for-720MHz-part.patch \
\
file://beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch \
file://beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch \
file://beagle/0003-OMAP3-beagle-add-MADC-support.patch \
file://beagle/0004-OMAP3-beagle-add-regulators-for-camera-interface.patch \
file://beagle/0005-OMAP3-beagle-HACK-add-in-1GHz-OPP.patch \
file://beagle/0006-OMAP3-BEAGLE-fix-RTC.patch \
file://beagle/0007-omap-mmc-Adjust-dto-to-eliminate-timeout-errors.patch \
\
file://camera/0001-Add-driver-for-Aptina-Micron-mt9p031-sensor.patch \
file://camera/0002-v4l-Add-mt9v032-sensor-driver.patch \
file://camera/0003-Add-support-for-mt9p031-LI-5M03-module-in-Beagleboar.patch \
\
file://pm/linux-omap-2.6.39-ti-pm/0001-OMAP3-voltage-remove-spurious-pr_notice-for-debugfs.patch \
file://pm/linux-omap-2.6.39-ti-pm/0002-OMAP4-PM-remove-redundant-ifdef-CONFIG_PM.patch \
file://pm/linux-omap-2.6.39-ti-pm/0003-OMAP3-smartreflex-fix-sr_late_init-error-path-in-pro.patch \
file://pm/linux-omap-2.6.39-ti-pm/0004-OMAP3-smartreflex-request-the-memory-region.patch \
file://pm/linux-omap-2.6.39-ti-pm/0005-OMAP3-smartreflex-fix-ioremap-leak-on-probe-error.patch \
file://pm/linux-omap-2.6.39-ti-pm/0006-OMAP3-smartreflex-delete-instance-from-sr_list-on-pr.patch \
file://pm/linux-omap-2.6.39-ti-pm/0007-OMAP3-smartreflex-delete-debugfs-entries-on-probe-er.patch \
file://pm/linux-omap-2.6.39-ti-pm/0008-OMAP3-cpuidle-remove-useless-SDP-specific-timings.patch \
file://pm/linux-omap-2.6.39-ti-pm/0009-OMAP3-SR-make-notify-independent-of-class.patch \
file://pm/linux-omap-2.6.39-ti-pm/0010-OMAP3-SR-disable-interrupt-by-default.patch \
file://pm/linux-omap-2.6.39-ti-pm/0011-OMAP3-SR-enable-disable-SR-only-on-need.patch \
file://pm/linux-omap-2.6.39-ti-pm/0012-OMAP3-SR-fix-cosmetic-indentation.patch \
\
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0001-OMAP-CPUfreq-ensure-driver-initializes-after-cpufreq.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0002-OMAP-CPUfreq-ensure-policy-is-fully-initialized.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0003-OMAP3-PM-CPUFreq-driver-for-OMAP3.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0004-OMAP-PM-CPUFREQ-Fix-conditional-compilation.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0005-cpufreq-fixup-after-new-OPP-layer-merged.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0006-OMAP-cpufreq-Split-OMAP1-and-OMAP2PLUS-CPUfreq-drive.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0007-OMAP2PLUS-cpufreq-Add-SMP-support-to-cater-OMAP4430.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq/0008-OMAP2PLUS-cpufreq-Fix-typo-when-attempting-to-set-mp.patch \
\
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-hotplug/0001-cpufreq-helpers-for-walking-the-frequency-table.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-hotplug/0002-cpufreq-introduce-hotplug-governor.patch \
\
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0001-OMAP2-cpufreq-free-up-table-on-exit.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0002-OMAP2-cpufreq-handle-invalid-cpufreq-table.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0003-OMAP2-cpufreq-minor-comment-cleanup.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0004-OMAP2-cpufreq-use-clk_init_cpufreq_table-if-OPPs-not.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0005-OMAP2-cpufreq-use-cpufreq_frequency_table_target.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpufreq-fixes/0006-OMAP2-cpufreq-fix-freq_table-leak.patch \
\
file://pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0001-OMAP2-clockdomain-Add-an-api-to-read-idle-mode.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0002-OMAP2-clockdomain-Add-SoC-support-for-clkdm_is_idle.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0003-OMAP2-PM-Initialise-sleep_switch-to-a-non-valid-valu.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0004-OMAP2-PM-idle-clkdms-only-if-already-in-idle.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0005-OMAP2-hwmod-Follow-the-recomended-PRCM-sequence.patch \
file://pm/linux-omap-2.6.39-ti-pm-wip-cpuidle/0006-OMAP-Serial-Check-wk_st-only-if-present.patch \
\
file://mfd/0001-mfd-Fix-omap-usbhs-crash-when-rmmoding-ehci-or-ohci.patch \
file://mfd/0002-mfd-Fix-omap_usbhs_alloc_children-error-handling.patch \
file://mfd/0003-mfd-Add-omap-usbhs-runtime-PM-support.patch \
file://mfd/0004-arm-omap-usb-ehci-and-ohci-hwmod-structures-for-omap.patch \
file://mfd/0005-arm-omap-usb-register-hwmods-of-usbhs.patch \
file://mfd/0006-arm-omap-usb-device-name-change-for-the-clk-names-of.patch \
file://mfd/0007-mfd-global-Suspend-and-resume-support-of-ehci-and-oh.patch \
file://mfd/0008-MFD-TWL4030-Correct-the-warning-print-during-script-.patch \
file://mfd/0009-MFD-TWL4030-Modifying-the-macro-name-Main_Ref-to-all.patch \
file://mfd/0010-MFD-TWL4030-power-scripts-for-OMAP3-boards.patch \
file://mfd/0011-MFD-TWL4030-TWL-version-checking.patch \
file://mfd/0012-MFD-TWL4030-workaround-changes-for-Erratum-27.patch \
file://mfd/0013-MFD-TWL4030-optimizing-resource-configuration.patch \
\
file://musb/0001-usb-musb-Enable-DMA-mode1-RX-for-USB-Mass-Storage.patch \
\
file://net/0001-NFS-Revert-NFSROOT-default-mount-options.patch \
"
SRC_URI_append_beagleboard = " file://logo_linux_clut224.ppm \
"
S = "${WORKDIR}/git"