summaryrefslogtreecommitdiff
path: root/drivers/staging/media/atomisp/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/media/atomisp/platform')
-rw-r--r--drivers/staging/media/atomisp/platform/Makefile1
-rw-r--r--drivers/staging/media/atomisp/platform/clock/Makefile6
-rw-r--r--drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.c40
-rw-r--r--drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h27
-rw-r--r--drivers/staging/media/atomisp/platform/clock/vlv2_plat_clock.c247
-rw-r--r--drivers/staging/media/atomisp/platform/intel-mid/Makefile1
-rw-r--r--drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c141
-rw-r--r--drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c297
8 files changed, 60 insertions, 700 deletions
diff --git a/drivers/staging/media/atomisp/platform/Makefile b/drivers/staging/media/atomisp/platform/Makefile
index df157630bda9..0e3b7e1c81c6 100644
--- a/drivers/staging/media/atomisp/platform/Makefile
+++ b/drivers/staging/media/atomisp/platform/Makefile
@@ -2,5 +2,4 @@
# Makefile for camera drivers.
#
-obj-$(CONFIG_INTEL_ATOMISP) += clock/
obj-$(CONFIG_INTEL_ATOMISP) += intel-mid/
diff --git a/drivers/staging/media/atomisp/platform/clock/Makefile b/drivers/staging/media/atomisp/platform/clock/Makefile
deleted file mode 100644
index 82fbe8b6968a..000000000000
--- a/drivers/staging/media/atomisp/platform/clock/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for clock devices.
-#
-
-obj-$(CONFIG_INTEL_ATOMISP) += vlv2_plat_clock.o
-obj-$(CONFIG_INTEL_ATOMISP) += platform_vlv2_plat_clk.o
diff --git a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.c b/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.c
deleted file mode 100644
index 0aae9b0283bb..000000000000
--- a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * platform_vlv2_plat_clk.c - VLV2 platform clock driver
- * Copyright (C) 2013 Intel Corporation
- *
- * Author: Asutosh Pathak <asutosh.pathak@intel.com>
- * Author: Chandra Sekhar Anagani <chandra.sekhar.anagani@intel.com>
- * Author: Sergio Aguirre <sergio.a.aguirre.rodriguez@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/printk.h>
-
-static int __init vlv2_plat_clk_init(void)
-{
- struct platform_device *pdev;
-
- pdev = platform_device_register_simple("vlv2_plat_clk", -1, NULL, 0);
- if (IS_ERR(pdev)) {
- pr_err("platform_vlv2_plat_clk:register failed: %ld\n",
- PTR_ERR(pdev));
- return PTR_ERR(pdev);
- }
-
- return 0;
-}
-
-device_initcall(vlv2_plat_clk_init);
diff --git a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h b/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h
deleted file mode 100644
index b730ab0e8223..000000000000
--- a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * platform_vlv2_plat_clk.h: platform clock driver library header file
- * Copyright (C) 2013 Intel Corporation
- *
- * Author: Asutosh Pathak <asutosh.pathak@intel.com>
- * Author: Chandra Sekhar Anagani <chandra.sekhar.anagani@intel.com>
- * Author: Sergio Aguirre <sergio.a.aguirre.rodriguez@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- */
-#ifndef _PLATFORM_VLV2_PLAT_CLK_H_
-#define _PLATFORM_VLV2_PLAT_CLK_H_
-
-#include <linux/sfi.h>
-#include <asm/intel-mid.h>
-
-extern void __init *vlv2_plat_clk_device_platform_data(
- void *info) __attribute__((weak));
-#endif
diff --git a/drivers/staging/media/atomisp/platform/clock/vlv2_plat_clock.c b/drivers/staging/media/atomisp/platform/clock/vlv2_plat_clock.c
deleted file mode 100644
index f96789a31819..000000000000
--- a/drivers/staging/media/atomisp/platform/clock/vlv2_plat_clock.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * vlv2_plat_clock.c - VLV2 platform clock driver
- * Copyright (C) 2013 Intel Corporation
- *
- * Author: Asutosh Pathak <asutosh.pathak@intel.com>
- * Author: Chandra Sekhar Anagani <chandra.sekhar.anagani@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include "../../include/linux/vlv2_plat_clock.h"
-
-/* NOTE: Most of below constants could come from platform data.
- * To be fixed when appropriate ACPI support comes.
- */
-#define VLV2_PMC_CLK_BASE_ADDRESS 0xfed03060
-#define PLT_CLK_CTL_OFFSET(x) (0x04 * (x))
-
-#define CLK_CONFG_BIT_POS 0
-#define CLK_CONFG_BIT_LEN 2
-#define CLK_CONFG_D3_GATED 0
-#define CLK_CONFG_FORCE_ON 1
-#define CLK_CONFG_FORCE_OFF 2
-
-#define CLK_FREQ_TYPE_BIT_POS 2
-#define CLK_FREQ_TYPE_BIT_LEN 1
-#define CLK_FREQ_TYPE_XTAL 0 /* 25 MHz */
-#define CLK_FREQ_TYPE_PLL 1 /* 19.2 MHz */
-
-#define MAX_CLK_COUNT 5
-
-/* Helper macros to manipulate bitfields */
-#define REG_MASK(n) (((1 << (n##_BIT_LEN)) - 1) << (n##_BIT_POS))
-#define REG_SET_FIELD(r, n, v) (((r) & ~REG_MASK(n)) | \
- (((v) << (n##_BIT_POS)) & REG_MASK(n)))
-#define REG_GET_FIELD(r, n) (((r) & REG_MASK(n)) >> n##_BIT_POS)
-/*
- * vlv2 platform has 6 platform clocks, controlled by 4 byte registers
- * Total size required for mapping is 6*4 = 24 bytes
- */
-#define PMC_MAP_SIZE 24
-
-static DEFINE_MUTEX(clk_mutex);
-static void __iomem *pmc_base;
-
-/*
- * vlv2_plat_set_clock_freq - Set clock frequency to a specified platform clock
- * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5)
- * @freq_type: Clock frequency (0-25 MHz(XTAL), 1-19.2 MHz(PLL) )
- */
-int vlv2_plat_set_clock_freq(int clk_num, int freq_type)
-{
- void __iomem *addr;
-
- if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) {
- pr_err("Clock number out of range (%d)\n", clk_num);
- return -EINVAL;
- }
-
- if (freq_type != CLK_FREQ_TYPE_XTAL &&
- freq_type != CLK_FREQ_TYPE_PLL) {
- pr_err("wrong clock type\n");
- return -EINVAL;
- }
-
- if (!pmc_base) {
- pr_err("memio map is not set\n");
- return -EINVAL;
- }
-
- addr = pmc_base + PLT_CLK_CTL_OFFSET(clk_num);
-
- mutex_lock(&clk_mutex);
- writel(REG_SET_FIELD(readl(addr), CLK_FREQ_TYPE, freq_type), addr);
- mutex_unlock(&clk_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vlv2_plat_set_clock_freq);
-
-/*
- * vlv2_plat_get_clock_freq - Get the status of specified platform clock
- * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5)
- *
- * Returns 0 for 25 MHz(XTAL) and 1 for 19.2 MHz(PLL)
- */
-int vlv2_plat_get_clock_freq(int clk_num)
-{
- u32 ret;
-
- if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) {
- pr_err("Clock number out of range (%d)\n", clk_num);
- return -EINVAL;
- }
-
- if (!pmc_base) {
- pr_err("memio map is not set\n");
- return -EINVAL;
- }
-
- mutex_lock(&clk_mutex);
- ret = REG_GET_FIELD(readl(pmc_base + PLT_CLK_CTL_OFFSET(clk_num)),
- CLK_FREQ_TYPE);
- mutex_unlock(&clk_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(vlv2_plat_get_clock_freq);
-
-/*
- * vlv2_plat_configure_clock - Configure the specified platform clock
- * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5)
- * @conf: Clock gating:
- * 0 - Clock gated on D3 state
- * 1 - Force on
- * 2,3 - Force off
- */
-int vlv2_plat_configure_clock(int clk_num, u32 conf)
-{
- void __iomem *addr;
-
- if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) {
- pr_err("Clock number out of range (%d)\n", clk_num);
- return -EINVAL;
- }
-
- if (conf != CLK_CONFG_D3_GATED &&
- conf != CLK_CONFG_FORCE_ON &&
- conf != CLK_CONFG_FORCE_OFF) {
- pr_err("Invalid clock configuration requested\n");
- return -EINVAL;
- }
-
- if (!pmc_base) {
- pr_err("memio map is not set\n");
- return -EINVAL;
- }
-
- addr = pmc_base + PLT_CLK_CTL_OFFSET(clk_num);
-
- mutex_lock(&clk_mutex);
- writel(REG_SET_FIELD(readl(addr), CLK_CONFG, conf), addr);
- mutex_unlock(&clk_mutex);
- return 0;
-}
-EXPORT_SYMBOL_GPL(vlv2_plat_configure_clock);
-
-/*
- * vlv2_plat_get_clock_status - Get the status of specified platform clock
- * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5)
- *
- * Returns 1 - On, 0 - Off
- */
-int vlv2_plat_get_clock_status(int clk_num)
-{
- int ret;
-
- if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) {
- pr_err("Clock number out of range (%d)\n", clk_num);
- return -EINVAL;
- }
-
- if (!pmc_base) {
- pr_err("memio map is not set\n");
- return -EINVAL;
- }
-
- mutex_lock(&clk_mutex);
- ret = (int)REG_GET_FIELD(readl(pmc_base + PLT_CLK_CTL_OFFSET(clk_num)),
- CLK_CONFG);
- mutex_unlock(&clk_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(vlv2_plat_get_clock_status);
-
-static int vlv2_plat_clk_probe(struct platform_device *pdev)
-{
- int i = 0;
-
- pmc_base = ioremap_nocache(VLV2_PMC_CLK_BASE_ADDRESS, PMC_MAP_SIZE);
- if (!pmc_base) {
- dev_err(&pdev->dev, "I/O memory remapping failed\n");
- return -ENOMEM;
- }
-
- /* Initialize all clocks as disabled */
- for (i = 0; i < MAX_CLK_COUNT; i++)
- vlv2_plat_configure_clock(i, CLK_CONFG_FORCE_OFF);
-
- dev_info(&pdev->dev, "vlv2_plat_clk initialized\n");
- return 0;
-}
-
-static const struct platform_device_id vlv2_plat_clk_id[] = {
- {"vlv2_plat_clk", 0},
- {}
-};
-
-static int vlv2_resume(struct device *device)
-{
- int i;
-
- /* Initialize all clocks as disabled */
- for (i = 0; i < MAX_CLK_COUNT; i++)
- vlv2_plat_configure_clock(i, CLK_CONFG_FORCE_OFF);
-
- return 0;
-}
-
-static int vlv2_suspend(struct device *device)
-{
- return 0;
-}
-
-static const struct dev_pm_ops vlv2_pm_ops = {
- .suspend = vlv2_suspend,
- .resume = vlv2_resume,
-};
-
-static struct platform_driver vlv2_plat_clk_driver = {
- .probe = vlv2_plat_clk_probe,
- .id_table = vlv2_plat_clk_id,
- .driver = {
- .name = "vlv2_plat_clk",
- .pm = &vlv2_pm_ops,
- },
-};
-
-static int __init vlv2_plat_clk_init(void)
-{
- return platform_driver_register(&vlv2_plat_clk_driver);
-}
-arch_initcall(vlv2_plat_clk_init);
diff --git a/drivers/staging/media/atomisp/platform/intel-mid/Makefile b/drivers/staging/media/atomisp/platform/intel-mid/Makefile
index 4621261c35db..c53db1364e21 100644
--- a/drivers/staging/media/atomisp/platform/intel-mid/Makefile
+++ b/drivers/staging/media/atomisp/platform/intel-mid/Makefile
@@ -1,5 +1,4 @@
#
# Makefile for intel-mid devices.
#
-obj-$(CONFIG_INTEL_ATOMISP) += intel_mid_pcihelpers.o
obj-$(CONFIG_INTEL_ATOMISP) += atomisp_gmin_platform.o
diff --git a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c
index edaae93af8f9..bf9f34b7ad72 100644
--- a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c
+++ b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c
@@ -4,10 +4,10 @@
#include <linux/efi.h>
#include <linux/pci.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <media/v4l2-subdev.h>
#include <linux/mfd/intel_soc_pmic.h>
-#include "../../include/linux/vlv2_plat_clock.h"
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio.h>
@@ -17,11 +17,7 @@
#define MAX_SUBDEVS 8
-/* Should be defined in vlv2_plat_clock API, isn't: */
-#define VLV2_CLK_PLL_19P2MHZ 1
-#define VLV2_CLK_XTAL_19P2MHZ 0
-#define VLV2_CLK_ON 1
-#define VLV2_CLK_OFF 2
+#define VLV2_CLK_PLL_19P2MHZ 1 /* XTAL on CHT */
#define ELDO1_SEL_REG 0x19
#define ELDO1_1P8V 0x16
#define ELDO1_CTRL_SHIFT 0x00
@@ -33,6 +29,8 @@ struct gmin_subdev {
struct v4l2_subdev *subdev;
int clock_num;
int clock_src;
+ bool clock_on;
+ struct clk *pmc_clk;
struct gpio_desc *gpio0;
struct gpio_desc *gpio1;
struct regulator *v1p8_reg;
@@ -108,49 +106,6 @@ const struct atomisp_platform_data *atomisp_get_platform_data(void)
}
EXPORT_SYMBOL_GPL(atomisp_get_platform_data);
-static int af_power_ctrl(struct v4l2_subdev *subdev, int flag)
-{
- struct gmin_subdev *gs = find_gmin_subdev(subdev);
-
- if (gs && gs->v2p8_vcm_on == flag)
- return 0;
- gs->v2p8_vcm_on = flag;
-
- /*
- * The power here is used for dw9817,
- * regulator is from rear sensor
- */
- if (gs->v2p8_vcm_reg) {
- if (flag)
- return regulator_enable(gs->v2p8_vcm_reg);
- else
- return regulator_disable(gs->v2p8_vcm_reg);
- }
- return 0;
-}
-
-/*
- * Used in a handful of modules. Focus motor control, I think. Note
- * that there is no configurability in the API, so this needs to be
- * fixed where it is used.
- *
- * struct camera_af_platform_data {
- * int (*power_ctrl)(struct v4l2_subdev *subdev, int flag);
- * };
- *
- * Note that the implementation in MCG platform_camera.c is stubbed
- * out anyway (i.e. returns zero from the callback) on BYT. So
- * neither needed on gmin platforms or supported upstream.
- */
-const struct camera_af_platform_data *camera_get_af_platform_data(void)
-{
- static struct camera_af_platform_data afpd = {
- .power_ctrl = af_power_ctrl,
- };
- return &afpd;
-}
-EXPORT_SYMBOL_GPL(camera_get_af_platform_data);
-
int atomisp_register_i2c_module(struct v4l2_subdev *subdev,
struct camera_sensor_platform_data *plat_data,
enum intel_v4l2_subdev_type type)
@@ -334,15 +289,8 @@ static const struct {
#define CFG_VAR_NAME_MAX 64
-static int gmin_platform_init(struct i2c_client *client)
-{
- return 0;
-}
-
-static int gmin_platform_deinit(void)
-{
- return 0;
-}
+#define GMIN_PMC_CLK_NAME 14 /* "pmc_plt_clk_[0..5]" */
+static char gmin_pmc_clk_name[GMIN_PMC_CLK_NAME];
static struct gmin_subdev *gmin_subdev_add(struct v4l2_subdev *subdev)
{
@@ -377,21 +325,42 @@ static struct gmin_subdev *gmin_subdev_add(struct v4l2_subdev *subdev)
gmin_subdevs[i].gpio0 = gpiod_get_index(dev, NULL, 0, GPIOD_OUT_LOW);
gmin_subdevs[i].gpio1 = gpiod_get_index(dev, NULL, 1, GPIOD_OUT_LOW);
- if (!IS_ERR(gmin_subdevs[i].gpio0)) {
- ret = gpiod_direction_output(gmin_subdevs[i].gpio0, 0);
- if (ret)
- dev_err(dev, "gpio0 set output failed: %d\n", ret);
- } else {
- gmin_subdevs[i].gpio0 = NULL;
+ /* get PMC clock with clock framework */
+ snprintf(gmin_pmc_clk_name,
+ sizeof(gmin_pmc_clk_name),
+ "%s_%d", "pmc_plt_clk", gmin_subdevs[i].clock_num);
+
+ gmin_subdevs[i].pmc_clk = devm_clk_get(dev, gmin_pmc_clk_name);
+ if (IS_ERR(gmin_subdevs[i].pmc_clk)) {
+ ret = PTR_ERR(gmin_subdevs[i].pmc_clk);
+
+ dev_err(dev,
+ "Failed to get clk from %s : %d\n",
+ gmin_pmc_clk_name,
+ ret);
+
+ return NULL;
}
- if (!IS_ERR(gmin_subdevs[i].gpio1)) {
- ret = gpiod_direction_output(gmin_subdevs[i].gpio1, 0);
- if (ret)
- dev_err(dev, "gpio1 set output failed: %d\n", ret);
- } else {
+ /*
+ * The firmware might enable the clock at
+ * boot (this information may or may not
+ * be reflected in the enable clock register).
+ * To change the rate we must disable the clock
+ * first to cover these cases. Due to common
+ * clock framework restrictions that do not allow
+ * to disable a clock that has not been enabled,
+ * we need to enable the clock first.
+ */
+ ret = clk_prepare_enable(gmin_subdevs[i].pmc_clk);
+ if (!ret)
+ clk_disable_unprepare(gmin_subdevs[i].pmc_clk);
+
+ if (IS_ERR(gmin_subdevs[i].gpio0))
+ gmin_subdevs[i].gpio0 = NULL;
+
+ if (IS_ERR(gmin_subdevs[i].gpio1))
gmin_subdevs[i].gpio1 = NULL;
- }
if (pmic_id == PMIC_REGULATOR) {
gmin_subdevs[i].v1p8_reg = regulator_get(dev, "V1P8SX");
@@ -539,13 +508,27 @@ static int gmin_flisclk_ctrl(struct v4l2_subdev *subdev, int on)
{
int ret = 0;
struct gmin_subdev *gs = find_gmin_subdev(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+
+ if (gs->clock_on == !!on)
+ return 0;
+
+ if (on) {
+ ret = clk_set_rate(gs->pmc_clk, gs->clock_src);
+
+ if (ret)
+ dev_err(&client->dev, "unable to set PMC rate %d\n",
+ gs->clock_src);
+
+ ret = clk_prepare_enable(gs->pmc_clk);
+ if (ret == 0)
+ gs->clock_on = true;
+ } else {
+ clk_disable_unprepare(gs->pmc_clk);
+ gs->clock_on = false;
+ }
- if (on)
- ret = vlv2_plat_set_clock_freq(gs->clock_num, gs->clock_src);
- if (ret)
- return ret;
- return vlv2_plat_configure_clock(gs->clock_num,
- on ? VLV2_CLK_ON : VLV2_CLK_OFF);
+ return ret;
}
static int gmin_csi_cfg(struct v4l2_subdev *sd, int flag)
@@ -592,8 +575,6 @@ static struct camera_sensor_platform_data gmin_plat = {
.v2p8_ctrl = gmin_v2p8_ctrl,
.v1p2_ctrl = gmin_v1p2_ctrl,
.flisclk_ctrl = gmin_flisclk_ctrl,
- .platform_init = gmin_platform_init,
- .platform_deinit = gmin_platform_deinit,
.csi_cfg = gmin_csi_cfg,
.get_vcm_ctrl = gmin_get_vcm_ctrl,
};
@@ -739,10 +720,8 @@ int camera_sensor_csi(struct v4l2_subdev *sd, u32 port,
if (flag) {
csi = kzalloc(sizeof(*csi), GFP_KERNEL);
- if (!csi) {
- dev_err(&client->dev, "out of memory\n");
+ if (!csi)
return -ENOMEM;
- }
csi->port = port;
csi->num_lanes = lanes;
csi->input_format = format;
diff --git a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c
deleted file mode 100644
index cd452cc20fea..000000000000
--- a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c
+++ /dev/null
@@ -1,297 +0,0 @@
-#include <linux/export.h>
-#include <linux/pci.h>
-#include <linux/pm_qos.h>
-#include <linux/delay.h>
-
-/* G-Min addition: "platform_is()" lives in intel_mid_pm.h in the MCG
- * tree, but it's just platform ID info and we don't want to pull in
- * the whole SFI-based PM architecture.
- */
-#define INTEL_ATOM_MRST 0x26
-#define INTEL_ATOM_MFLD 0x27
-#define INTEL_ATOM_CLV 0x35
-#define INTEL_ATOM_MRFLD 0x4a
-#define INTEL_ATOM_BYT 0x37
-#define INTEL_ATOM_MOORFLD 0x5a
-#define INTEL_ATOM_CHT 0x4c
-/* synchronization for sharing the I2C controller */
-#define PUNIT_PORT 0x04
-#define PUNIT_DOORBELL_OPCODE (0xE0)
-#define PUNIT_DOORBELL_REG (0x0)
-#ifndef CSTATE_EXIT_LATENCY
-#define CSTATE_EXIT_LATENCY_C1 1
-#endif
-static inline int platform_is(u8 model)
-{
- return (boot_cpu_data.x86_model == model);
-}
-
-#include "../../include/asm/intel_mid_pcihelpers.h"
-
-/* Unified message bus read/write operation */
-static DEFINE_SPINLOCK(msgbus_lock);
-
-static struct pci_dev *pci_root;
-static struct pm_qos_request pm_qos;
-
-#define DW_I2C_NEED_QOS (platform_is(INTEL_ATOM_BYT))
-
-static int intel_mid_msgbus_init(void)
-{
- pci_root = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
- if (!pci_root) {
- pr_err("%s: Error: msgbus PCI handle NULL\n", __func__);
- return -ENODEV;
- }
-
- if (DW_I2C_NEED_QOS) {
- pm_qos_add_request(&pm_qos,
- PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
- }
- return 0;
-}
-fs_initcall(intel_mid_msgbus_init);
-
-u32 intel_mid_msgbus_read32_raw(u32 cmd)
-{
- unsigned long irq_flags;
- u32 data;
-
- spin_lock_irqsave(&msgbus_lock, irq_flags);
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
- pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data);
- spin_unlock_irqrestore(&msgbus_lock, irq_flags);
-
- return data;
-}
-EXPORT_SYMBOL(intel_mid_msgbus_read32_raw);
-
-/*
- * GU: this function is only used by the VISA and 'VXD' drivers.
- */
-u32 intel_mid_msgbus_read32_raw_ext(u32 cmd, u32 cmd_ext)
-{
- unsigned long irq_flags;
- u32 data;
-
- spin_lock_irqsave(&msgbus_lock, irq_flags);
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG, cmd_ext);
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
- pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data);
- spin_unlock_irqrestore(&msgbus_lock, irq_flags);
-
- return data;
-}
-EXPORT_SYMBOL(intel_mid_msgbus_read32_raw_ext);
-
-void intel_mid_msgbus_write32_raw(u32 cmd, u32 data)
-{
- unsigned long irq_flags;
-
- spin_lock_irqsave(&msgbus_lock, irq_flags);
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data);
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
- spin_unlock_irqrestore(&msgbus_lock, irq_flags);
-}
-EXPORT_SYMBOL(intel_mid_msgbus_write32_raw);
-
-/*
- * GU: this function is only used by the VISA and 'VXD' drivers.
- */
-void intel_mid_msgbus_write32_raw_ext(u32 cmd, u32 cmd_ext, u32 data)
-{
- unsigned long irq_flags;
-
- spin_lock_irqsave(&msgbus_lock, irq_flags);
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data);
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG, cmd_ext);
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
- spin_unlock_irqrestore(&msgbus_lock, irq_flags);
-}
-EXPORT_SYMBOL(intel_mid_msgbus_write32_raw_ext);
-
-u32 intel_mid_msgbus_read32(u8 port, u32 addr)
-{
- unsigned long irq_flags;
- u32 data;
- u32 cmd;
- u32 cmdext;
-
- cmd = (PCI_ROOT_MSGBUS_READ << 24) | (port << 16) |
- ((addr & 0xff) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
- cmdext = addr & 0xffffff00;
-
- spin_lock_irqsave(&msgbus_lock, irq_flags);
-
- if (cmdext) {
- /* This resets to 0 automatically, no need to write 0 */
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG,
- cmdext);
- }
-
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
- pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data);
- spin_unlock_irqrestore(&msgbus_lock, irq_flags);
-
- return data;
-}
-EXPORT_SYMBOL(intel_mid_msgbus_read32);
-
-void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data)
-{
- unsigned long irq_flags;
- u32 cmd;
- u32 cmdext;
-
- cmd = (PCI_ROOT_MSGBUS_WRITE << 24) | (port << 16) |
- ((addr & 0xFF) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
- cmdext = addr & 0xffffff00;
-
- spin_lock_irqsave(&msgbus_lock, irq_flags);
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data);
-
- if (cmdext) {
- /* This resets to 0 automatically, no need to write 0 */
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG,
- cmdext);
- }
-
- pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd);
- spin_unlock_irqrestore(&msgbus_lock, irq_flags);
-}
-EXPORT_SYMBOL(intel_mid_msgbus_write32);
-
-/* called only from where is later then fs_initcall */
-u32 intel_mid_soc_stepping(void)
-{
- return pci_root->revision;
-}
-EXPORT_SYMBOL(intel_mid_soc_stepping);
-
-static bool is_south_complex_device(struct pci_dev *dev)
-{
- unsigned int base_class = dev->class >> 16;
- unsigned int sub_class = (dev->class & SUB_CLASS_MASK) >> 8;
-
- /* other than camera, pci bridges and display,
- * everything else are south complex devices.
- */
- if (((base_class == PCI_BASE_CLASS_MULTIMEDIA) &&
- (sub_class == ISP_SUB_CLASS)) ||
- (base_class == PCI_BASE_CLASS_BRIDGE) ||
- ((base_class == PCI_BASE_CLASS_DISPLAY) && !sub_class))
- return false;
- else
- return true;
-}
-
-/* In BYT platform, d3_delay for internal south complex devices,
- * they are not subject to 10 ms d3 to d0 delay required by pci spec.
- */
-static void pci_d3_delay_fixup(struct pci_dev *dev)
-{
- if (platform_is(INTEL_ATOM_BYT) ||
- platform_is(INTEL_ATOM_CHT)) {
- /* All internal devices are in bus 0. */
- if (dev->bus->number == 0 && is_south_complex_device(dev)) {
- dev->d3_delay = INTERNAL_PCI_PM_D3_WAIT;
- dev->d3cold_delay = INTERNAL_PCI_PM_D3_WAIT;
- }
- }
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3_delay_fixup);
-
-#define PUNIT_SEMAPHORE (platform_is(INTEL_ATOM_BYT) ? 0x7 : 0x10E)
-#define GET_SEM() (intel_mid_msgbus_read32(PUNIT_PORT, PUNIT_SEMAPHORE) & 0x1)
-
-static void reset_semaphore(void)
-{
- u32 data;
-
- data = intel_mid_msgbus_read32(PUNIT_PORT, PUNIT_SEMAPHORE);
- smp_mb();
- data = data & 0xfffffffc;
- intel_mid_msgbus_write32(PUNIT_PORT, PUNIT_SEMAPHORE, data);
- smp_mb();
-
-}
-
-int intel_mid_dw_i2c_acquire_ownership(void)
-{
- u32 ret = 0;
- u32 data = 0; /* data sent to PUNIT */
- u32 cmd;
- u32 cmdext;
- int timeout = 1000;
-
- if (DW_I2C_NEED_QOS)
- pm_qos_update_request(&pm_qos, CSTATE_EXIT_LATENCY_C1 - 1);
-
- /*
- * We need disable irq. Otherwise, the main thread
- * might be preempted and the other thread jumps to
- * disable irq for a long time. Another case is
- * some irq handlers might trigger power voltage change
- */
- BUG_ON(irqs_disabled());
- local_irq_disable();
-
- /* host driver writes 0x2 to side band register 0x7 */
- intel_mid_msgbus_write32(PUNIT_PORT, PUNIT_SEMAPHORE, 0x2);
- smp_mb();
-
- /* host driver sends 0xE0 opcode to PUNIT and writes 0 register */
- cmd = (PUNIT_DOORBELL_OPCODE << 24) | (PUNIT_PORT << 16) |
- ((PUNIT_DOORBELL_REG & 0xFF) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE;
- cmdext = PUNIT_DOORBELL_REG & 0xffffff00;
-
- if (cmdext)
- intel_mid_msgbus_write32_raw_ext(cmd, cmdext, data);
- else
- intel_mid_msgbus_write32_raw(cmd, data);
-
- /* host driver waits for bit 0 to be set in side band 0x7 */
- while (GET_SEM() != 0x1) {
- udelay(100);
- timeout--;
- if (timeout <= 0) {
- pr_err("Timeout: semaphore timed out, reset sem\n");
- ret = -ETIMEDOUT;
- reset_semaphore();
- /*Delay 1ms in case race with punit*/
- udelay(1000);
- if (GET_SEM() != 0) {
- /*Reset again as kernel might race with punit*/
- reset_semaphore();
- }
- pr_err("PUNIT SEM: %d\n",
- intel_mid_msgbus_read32(PUNIT_PORT,
- PUNIT_SEMAPHORE));
- local_irq_enable();
-
- if (DW_I2C_NEED_QOS) {
- pm_qos_update_request(&pm_qos,
- PM_QOS_DEFAULT_VALUE);
- }
-
- return ret;
- }
- }
- smp_mb();
-
- return ret;
-}
-EXPORT_SYMBOL(intel_mid_dw_i2c_acquire_ownership);
-
-int intel_mid_dw_i2c_release_ownership(void)
-{
- reset_semaphore();
- local_irq_enable();
-
- if (DW_I2C_NEED_QOS)
- pm_qos_update_request(&pm_qos, PM_QOS_DEFAULT_VALUE);
-
- return 0;
-}
-EXPORT_SYMBOL(intel_mid_dw_i2c_release_ownership);