diff options
Diffstat (limited to 'drivers/staging/media/atomisp/platform')
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); |