+++ /dev/null
-/*
- * intel_mid_vdd.c - Intel Clovertrail Platform Voltage Drop Detection Driver
- *
- *
- * Copyright (C) 2010 Intel Corporation
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * 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.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * Author: Durgadoss R <durgadoss.r@intel.com>
- * Chaurasia, Avinash K <avinash.k.chaurasia@intel.com>
- *
- * This driver monitors the voltage level of the system. When the voltage
- * drops below a programmed threshold, it notifies the CPU of the drop.
- * Also, the driver configures the HW to take some actions to prevent
- * system crash due to sudden drop in voltage. The HW unit that does all
- * these, is named as Burst Control Unit(BCU).
- */
-
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ipc_device.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/hwmon.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/timer.h>
-#include <asm/intel_scu_ipc.h>
-#include <linux/kfifo.h>
-
-#define DRIVER_NAME "msic_ocd"
-#define DEVICE_NAME "msic_ocd"
-
-/* BCU registers that govern voltage monitoring */
-#define VWARNA_CFG 0x109
-#define VWARNB_CFG 0x10A
-#define VCRIT_CFG 0x10B
-
-/* BCU registers that control the behaviour of output signals */
-#define BCUDISA_BEH 0x10C
-#define BCUDISB_BEH 0x10D
-#define BCUDISCRIT_BEH 0x10E
-#define BCUPROCHOT_BEH 0x10F
-
-/* BCU Interrupt registers */
-#define BCUIRQ 0x00A
-#define MBCUIRQ 0x019
-
-/* BCU Status registers */
-#define SBCUIRQ 0x110
-#define SBCUCTRL 0x111
-
-#define IRQLVL1MSK 0x021
-/* Voltage limits (in mV) */
-#define MAX_VOLTAGE 3300
-#define MIN_VOLTAGE 2600
-
-/* Number of voltage levels: WarnA, WarnB, Crit */
-#define NUM_VOLT_LEVELS 3
-
-/* Number of BCU Behavior registers: 0x10C -> 0x10F */
-#define NUM_BEH_REGS 4
-
-/* BCUIRQ register settings */
-#define VCRIT_IRQ (1 << 2)
-#define VWARNA_IRQ (1 << 1)
-#define VWARNB_IRQ (1 << 0)
-
-#define VCOMP_ENABLE (1 << 3) /* Enable BCU voltage comparator */
-#define BCU_STICKY (1 << 2) /* BCU output signal stickiness */
-#define BCU_POLARITY (1 << 1) /* BCU output signal polarity */
-#define BCU_OUT_EN (1 << 0) /* Enable BCU output signal */
-
-/*BCU real time status flags for corresponding signals*/
-#define SVWARNB (1<<0)
-#define SVWARNA (1<<1)
-#define SVCRIT (1<<2)
-/**curently 20 fast clock is set */
-#define DEBOUNCE (0x70)
-/**currently 000 is set which is equal to 3.3V ***/
-#define VWARNA_VOLT_THRES 0x04
-#define VWARNB_VOLT_THRES 0x04
-#define VCRIT_VOLT_THRES 0x01
-/* check whether bit is sticky or not by checking 3rd bit */
-#define IS_STICKY(data) (data&4)
-/* clear assert by writing 1 to appropiate bit of SBCUCTRL */
-#define CLEAR_ASSERT(bit) (1<<bit)
-/* masking the bit */
-#define MASK_BIT(bit) (1<<bit)
-#define CLEAR_BIT(bit) (~(1<<bit))
-/*This will be used to set/clear the correct bit
-in the registers based on enum defined below*/
-#define FIXED_TIME 6
-#define RESETTING_VALUE 6
-#define BCU_STATUS(data) ((data ^ 1)<<3)
-#define RSHIFT_VALUE(data, bit) (data >> bit)
-/* value can be 0 or 1 only and bit starts from 0 not 1*/
-#define SET(data, value, bit) ((data & (~(1<<bit)))|((value)<<bit))
-#define SET_ACTION_MASK(data, value, bit) (data | (value << bit))
-
-/*This macro is used in hardcoding of gpio */
-#define GPIO_OCD 36
-#define MSIC_BCU_STAT 0xFFFF7FC8
-#define MSIC_BCU_LEN 1
-#define IRQ_FIFO_MAX 16
-#define IRQ_KFIFO_ELEMENT 1
-
-
-enum { VWARNB_EVENT = 1, VWARNA_EVENT = 2, VCRIT_EVENT = 4};
-
-static DEFINE_MUTEX(vdd_update_lock);
-/** defining the fifo to store the interrupt value ***/
-static DEFINE_KFIFO(irq_fifo, u8, IRQ_FIFO_MAX);
-static struct timer_list masking_timer, spurious_timer;
-static int debouncing_time_after_timer_expired = RESETTING_VALUE;
-struct vdd_info {
- unsigned int irq;
- struct device *dev;
- struct ipc_device *pdev;
- /* Cached value of the status register, since the last interrupt */
- unsigned int intrpt_status;
- void __iomem *bcu_stat;
-};
-
-static inline int vdd_set_bits(u16 addr, u8 mask)
-{
- return intel_scu_ipc_update_register(addr, 0xff, mask);
-}
-
-static ssize_t store_action_mask(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int ret;
- uint8_t data;
- long assertPin;
- dev_dbg(dev, "@@@ store_action_mask\n");
- if (strict_strtol(buf, 10, &assertPin))
- return -EINVAL;
-
- if (assertPin < 0 || assertPin > 0x1F)
- return -EINVAL;
-
- mutex_lock(&vdd_update_lock);
- ret = intel_scu_ipc_update_register(BCUDISA_BEH,
- (RSHIFT_VALUE(assertPin, 0) & 1), 0x01);
- if (ret)
- goto mask_ipc_fail;
- ret = intel_scu_ipc_update_register(BCUDISB_BEH,
- (RSHIFT_VALUE(assertPin, 1) & 1), 0x01);
- if (ret)
- goto mask_ipc_fail;
- ret = intel_scu_ipc_update_register(BCUDISCRIT_BEH,
- (RSHIFT_VALUE(assertPin, 2) & 1), 0x01);
- if (ret)
- goto mask_ipc_fail;
- ret = intel_scu_ipc_update_register(BCUPROCHOT_BEH,
- (RSHIFT_VALUE(assertPin, 3) & 1)<<1, 0x02);
- if (ret)
- goto mask_ipc_fail;
- ret = intel_scu_ipc_update_register(BCUPROCHOT_BEH,
- (RSHIFT_VALUE(assertPin, 4) & 1), 0x01);
- if (ret)
- goto mask_ipc_fail;
- dev_dbg(dev, "@@@ storeaction_mask %d\n", assertPin);
- ret = count;
-mask_ipc_fail:
- mutex_unlock(&vdd_update_lock);
- return ret;
-
-}
-
-static ssize_t show_action_mask(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int ret;
- uint8_t data;
- long assertPin = 0;
- dev_dbg(dev, "@@@ show_action_mask\n");
-
- mutex_lock(&vdd_update_lock);
- ret = intel_scu_ipc_ioread8(BCUDISA_BEH, &data);
- if (ret)
- goto mask_ipc_fail;
- assertPin = SET_ACTION_MASK(assertPin, (data & 1), 0);
- ret = intel_scu_ipc_ioread8(BCUDISB_BEH, &data);
- if (ret)
- goto mask_ipc_fail;
- assertPin = SET_ACTION_MASK(assertPin, (data & 1), 1);
- ret = intel_scu_ipc_ioread8(BCUDISCRIT_BEH, &data);
- if (ret)
- goto mask_ipc_fail;
- assertPin = SET_ACTION_MASK(assertPin, (data & 1), 2);
- ret = intel_scu_ipc_ioread8(BCUPROCHOT_BEH, &data);
- if (ret)
- goto mask_ipc_fail;
- assertPin = SET_ACTION_MASK(assertPin, ((data>>1) & 1), 3);
- ret = intel_scu_ipc_ioread8(BCUPROCHOT_BEH, &data);
- if (ret)
- goto mask_ipc_fail;
- assertPin = SET_ACTION_MASK(assertPin, (data & 1), 4);
-mask_ipc_fail:
- dev_dbg(dev, "@@@ show_action_mask:%x @@@\n", assertPin);
- mutex_unlock(&vdd_update_lock);
- return sprintf(buf, "%x\n", assertPin);
-}
-
-static ssize_t change_bcu_status(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int ret;
- uint8_t data;
- long bcu_enable;
-
- dev_dbg(dev, "@@@ change bcu status @@@\n");
- if (strict_strtol(buf, 10, &bcu_enable))
- return -EINVAL;
- if (bcu_enable != 0 && bcu_enable != 1)
- return -EINVAL;
-
- mutex_lock(&vdd_update_lock);
- /* bc_enable = 0 means enable bcu */
- ret = intel_scu_ipc_update_register(VWARNA_CFG,
- BCU_STATUS(bcu_enable), 0x08);
- if (ret)
- goto bcu_ipc_fail;
- ret = intel_scu_ipc_update_register(VWARNB_CFG,
- BCU_STATUS(bcu_enable), 0x08);
- if (ret)
- goto bcu_ipc_fail;
- ret = intel_scu_ipc_update_register(VCRIT_CFG,
- BCU_STATUS(bcu_enable), 0x08);
- if (ret)
- goto bcu_ipc_fail;
-
-
- dev_dbg(dev, "@@@ change_bcu_status:%d @@@\n", bcu_enable);
- ret = count;
-bcu_ipc_fail:
- mutex_unlock(&vdd_update_lock);
- return ret;
-}
-
-static ssize_t show_bcu_status(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int ret, bcu_enable;
- uint8_t data;
-
- dev_dbg(dev, "@@@ show_bcu_status @@@\n");
- ret = intel_scu_ipc_ioread8(VWARNA_CFG, &data);
- if (ret)
- return ret;
- bcu_enable = ((data >> 3) & 0x01) ^ 1;
- dev_dbg(dev, "@@@ show_bcu_status:%d @@@\n", bcu_enable);
- return sprintf(buf, "%d\n", bcu_enable);
-}
-
-static ssize_t store_volt_thres(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int ret;
- uint8_t data;
- long volt;
- struct sensor_device_attribute_2 *s_attr =
- to_sensor_dev_attr_2(attr);
-
- dev_dbg(dev, "@@@ store_volt_thres @@@\n");
- if (strict_strtol(buf, 10, &volt))
- return -EINVAL;
-
- if (volt > MAX_VOLTAGE || volt < MIN_VOLTAGE)
- return -EINVAL;
-
- mutex_lock(&vdd_update_lock);
-
- ret = intel_scu_ipc_ioread8(VWARNA_CFG + s_attr->nr, &data);
- if (ret)
- goto ipc_fail;
-
- dev_dbg(dev, "@@@ store_volt_thres-volt:%u, data:%u @@@\n", volt, data);
- /*
- * The VWARN*_CFG registers hold 7 voltage values, in [0-2]
- * bits. 3.3v corresponds to 0 and 2.6v corresponds to 7. So,
- * find the difference(diff) from MAX_VOLTAGE and divide it by
- * 100(since the values are entered as mV). Then, set bits
- * [0-2] to 'diff'
- */
- data = (data & 0xF8) | ((MAX_VOLTAGE - volt)/100);
-
- ret = intel_scu_ipc_iowrite8(VWARNA_CFG + s_attr->nr, data);
- if (ret)
- goto ipc_fail;
-
- ret = count;
-
-ipc_fail:
- mutex_unlock(&vdd_update_lock);
- return ret;
-}
-
-static ssize_t show_volt_thres(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int ret, volt;
- uint8_t data;
- struct sensor_device_attribute_2 *s_attr =
- to_sensor_dev_attr_2(attr);
-
- dev_dbg(dev, "@@@ show_volt_thres @@@\n");
- ret = intel_scu_ipc_ioread8(VWARNA_CFG + s_attr->nr, &data);
- if (ret)
- return ret;
-
- /* Read bits [0-2] of data and multiply by 100(for mV) */
- volt = (data & 0x07) * 100;
-
- dev_dbg(dev, "@@@ show_volt_thres-volt:%u mV, data:%u @@@\n",
- MAX_VOLTAGE-volt, data);
- return sprintf(buf, "%d\n", MAX_VOLTAGE - volt);
-}
-
-static ssize_t show_irq_status(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int ret;
- uint8_t irq_status;
-
- dev_dbg(dev, "@@@ show_irq_status @@@\n");
- ret = intel_scu_ipc_ioread8(SBCUIRQ, &irq_status);
- if (ret)
- return ret;
-
- return sprintf(buf, "%x\n", irq_status);
-}
-
-static ssize_t show_action_status(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- uint8_t action_status;
- int ret;
-
- dev_dbg(dev, "@@@ show_action_mask @@@\n");
- ret = intel_scu_ipc_ioread8(SBCUCTRL, &action_status);
- if (ret)
- return ret;
-
- return sprintf(buf, "%x\n", action_status);
-}
-
-static void timer_platform_ready_tohandle(unsigned long data)
-{
- int ret;
- ret = intel_scu_ipc_update_register(MBCUIRQ, CLEAR_BIT(2), 0x04);
- if (ret)
- goto platform_exit;
- /******* have to check whether interrupt is clear or not */
-platform_exit:
- if (!timer_pending(&spurious_timer)) {
- spurious_timer.expires = msecs_to_jiffies(RESETTING_VALUE);
- add_timer(&spurious_timer);
- }
-}
-
-static void timer_spurious_cleared(unsigned long data)
-{
- int ret;
- uint8_t irq_data, sticky_data;
- ret = intel_scu_ipc_ioread8(SBCUIRQ, &irq_data);
- if (!(irq_data & 4)) {
- ret = intel_scu_ipc_ioread8(BCUDISCRIT_BEH, &sticky_data);
- if (ret)
- goto spurious_ipc_fail;
- if (IS_STICKY(sticky_data)) {
- mutex_lock(&vdd_update_lock);
- ret = intel_scu_ipc_update_register(SBCUCTRL,
- CLEAR_ASSERT(1), 0x02);
- mutex_unlock(&vdd_update_lock);
- if (ret)
- goto spurious_ipc_fail;
- }
- }
-spurious_ipc_fail:
- return;
-}
-
-static void handle_events(int flag, void *dev_data)
-{
- /*flag can have any of these values
- VCRIT_EVENT, VWARNA_EVENT, VWARNB_EVENT;*/
- uint8_t irq_data, sticky_data;
- struct vdd_info *vinfo = (struct vdd_info *)dev_data;
- int ret;
- /* This variable is to inform calling function
- about the mutex state */
- ret = intel_scu_ipc_ioread8(SBCUIRQ, &irq_data);
- if (ret)
- goto handle_ipc_fail;
-
- if (flag & VCRIT_EVENT) {
- dev_dbg(&vinfo->pdev->dev, "vdd VCRIT goes low\n");
- if (irq_data & SVCRIT) {
- /*interrupt up for VCRIT */
- if (!timer_pending(&spurious_timer)) {
- masking_timer.expires =
- msecs_to_jiffies(FIXED_TIME +
- debouncing_time_after_timer_expired);
- debouncing_time_after_timer_expired +=
- RESETTING_VALUE;
- } else {
- debouncing_time_after_timer_expired =
- RESETTING_VALUE;
- masking_timer.expires =
- msecs_to_jiffies(FIXED_TIME);
- }
- ret = intel_scu_ipc_update_register(MBCUIRQ,
- MASK_BIT(2), 0x04);
- add_timer(&masking_timer);
- } else {
- /*interrupt cleared*/
- ret = intel_scu_ipc_ioread8(BCUDISCRIT_BEH,
- &sticky_data);
- if (ret)
- goto handle_ipc_fail;
- if (IS_STICKY(sticky_data)) {
- ret = intel_scu_ipc_update_register(SBCUCTRL,
- CLEAR_ASSERT(1), 0x02);
- if (ret)
- goto handle_ipc_fail;
- }
- }
- }
- if (flag & VWARNB_EVENT) {
- dev_dbg(&vinfo->pdev->dev, "vdd VWARNB hits\n");
- if (irq_data & SVWARNB) {
- /*interrupt up for WARNB*/
- ret = intel_scu_ipc_update_register(BCUDISB_BEH,
- BCU_STICKY, 0x04);
- if (ret)
- goto handle_ipc_fail;
- } else {
- /*interrupt cleared*/
- ret = intel_scu_ipc_update_register(BCUDISB_BEH,
- ~BCU_STICKY, 0x04);
- if (ret)
- goto handle_ipc_fail;
- if (IS_STICKY(sticky_data)) {
- ret = intel_scu_ipc_update_register(SBCUCTRL,
- CLEAR_ASSERT(2), 0x04);
- if (ret)
- goto handle_ipc_fail;
- }
- }
- }
- if (flag & VWARNA_EVENT) {
- dev_dbg(&vinfo->pdev->dev, "vdd VWARNA hits\n");
- if (irq_data & SVWARNA) {
- /*interrupt up for WARNA*/
- ret = intel_scu_ipc_update_register(BCUDISA_BEH,
- BCU_STICKY, 0x04);
- if (ret)
- goto handle_ipc_fail;
- } else {
- /*interrupt cleared*/
- ret = intel_scu_ipc_update_register(BCUDISA_BEH,
- ~BCU_STICKY, 0x04);
- if (ret)
- goto handle_ipc_fail;
- if (IS_STICKY(sticky_data)) {
- ret = intel_scu_ipc_update_register(SBCUCTRL,
- CLEAR_ASSERT(3), 0x08);
- if (ret)
- goto handle_ipc_fail;
- }
- }
- }
- kobject_uevent(&vinfo->pdev->dev.kobj, KOBJ_CHANGE);
- return;
-handle_ipc_fail:
- kobject_uevent(&vinfo->pdev->dev.kobj, KOBJ_CHANGE);
- dev_dbg(&vinfo->pdev->dev, "ipc read/write failed");
- return;
-}
-
-static irqreturn_t vdd_intrpt_handler(int id, void *dev)
-{
- struct vdd_info *vinfo = (struct vdd_info *)dev;
- uint8_t irq_data;
- if (unlikely(kfifo_is_full(&irq_fifo)))
- return IRQ_WAKE_THREAD;
-
- irq_data = readb(vinfo->bcu_stat);
- kfifo_in(&irq_fifo, &irq_data, IRQ_KFIFO_ELEMENT);
- return IRQ_WAKE_THREAD;
-};
-
-static irqreturn_t vdd_intrptThread_handler(int irq, void *dev_data)
-{
- int ret;
- uint8_t irq_data, event;
- struct vdd_info *vinfo = (struct vdd_info *)dev_data;
-
- dev_dbg(&vinfo->pdev->dev, "*** 4:26 vdd_handle_intrp **");
-
- if (!vinfo)
- return IRQ_NONE;
-
- if (unlikely(kfifo_is_empty(&irq_fifo))) {
- dev_dbg(&vinfo->pdev->dev, "*** 4:26 vdd IRQ empty fifo\n");
- return IRQ_NONE;
- }
- ret = kfifo_out(&irq_fifo, &irq_data, IRQ_KFIFO_ELEMENT);
- if (ret != IRQ_KFIFO_ELEMENT) {
- dev_dbg(&vinfo->pdev->dev, "*** 4:26 vdd KFIFO underflow\n");
- return IRQ_NONE;
- }
-
- mutex_lock(&vdd_update_lock);
- /* BCU VCRIT crossing Interrupt */
- if (irq_data & VCRIT_IRQ) /* BCU VCRIT Interrupt */
- event = VCRIT_EVENT;
- else if (irq_data & VWARNA_IRQ) /* BCU WARNA Interrupt */
- event = VWARNA_EVENT;
- else /* BCU WARNB Interrupt */
- event = VWARNB_EVENT;
-
- handle_events(event, dev_data);
-
- /* it will be locked only when handle_events don't hold the lock */
-
- /* Set the corresponding bit to clear the Interrupt */
- mutex_unlock(&vdd_update_lock);
- return IRQ_HANDLED;
-}
-
-
-static SENSOR_DEVICE_ATTR_2(voltage_warnA, S_IRUGO | S_IWUSR,
- show_volt_thres, store_volt_thres, 0, 0);
-static SENSOR_DEVICE_ATTR_2(voltage_warnB, S_IRUGO | S_IWUSR,
- show_volt_thres, store_volt_thres, 1, 0);
-static SENSOR_DEVICE_ATTR_2(voltage_warn_crit, S_IRUGO | S_IWUSR,
- show_volt_thres, store_volt_thres, 2, 0);
-static SENSOR_DEVICE_ATTR_2(action_mask, S_IRUGO | S_IWUSR, show_action_mask,
- store_action_mask, 0, 0);
-static SENSOR_DEVICE_ATTR_2(bcu_status, S_IRUGO | S_IWUSR, show_bcu_status,
- change_bcu_status, 0, 0);
-static SENSOR_DEVICE_ATTR_2(irq_status, S_IRUGO, show_irq_status,
- NULL, 0, 0);
-static SENSOR_DEVICE_ATTR_2(action_status, S_IRUGO, show_action_status,
- NULL, 0, 0);
-
-static struct attribute *mid_vdd_attrs[] = {
- &sensor_dev_attr_voltage_warnA.dev_attr.attr,
- &sensor_dev_attr_voltage_warnB.dev_attr.attr,
- &sensor_dev_attr_voltage_warn_crit.dev_attr.attr,
- &sensor_dev_attr_action_mask.dev_attr.attr,
- &sensor_dev_attr_bcu_status.dev_attr.attr,
- &sensor_dev_attr_irq_status.dev_attr.attr,
- &sensor_dev_attr_action_status.dev_attr.attr,
- NULL
-};
-
-static struct attribute_group mid_vdd_gr = {
- .name = "msic_voltage",
- .attrs = mid_vdd_attrs
-};
-
-static int mid_vdd_probe(struct ipc_device *pdev)
-{
- int i, ret;
- struct vdd_info *vinfo = devm_kzalloc(&pdev->dev,
- sizeof(struct vdd_info), GFP_KERNEL);
- uint8_t mbcu_data;
- dev_dbg(&pdev->dev, "*** 4:26 mid_vdd_probe ***\n");
- if (!vinfo) {
- dev_dbg(&pdev->dev, "kzalloc failed\n");
- return -ENOMEM;
- }
-
- vinfo->pdev = pdev;
- vinfo->irq = ipc_get_irq(pdev, 0);
- /** its a hack for IA*/
- vinfo->irq = GPIO_OCD;
- ipc_set_drvdata(pdev, vinfo);
-
-
- vinfo->bcu_stat = ioremap(MSIC_BCU_STAT, MSIC_BCU_LEN);
- if (!vinfo->bcu_stat) {
- dev_dbg(&pdev->dev,
- "*** 4:26 mid_vdd_probe bcu_stat failed ***\n");
- return -ENOMEM;
- }
- /* Enable Voltage Comparator logic for all warning levels */
- for (i = 0; i < NUM_VOLT_LEVELS; i++)
- vdd_set_bits(VWARNA_CFG + i, VCOMP_ENABLE);
-
- /* Enable BCU output signals for all warning levels */
- for (i = 0; i < NUM_BEH_REGS; i++)
- vdd_set_bits(BCUDISA_BEH + i, BCU_OUT_EN);
-
- /* Creating a sysfs group with mid_vdd_gr attributes */
- ret = sysfs_create_group(&pdev->dev.kobj, &mid_vdd_gr);
- if (ret) {
- dev_dbg(&pdev->dev, "vdd sysfs_create_group failed\n");
- goto vdd_error1;
- }
- printk(KERN_ERR "*** 8:49 mid_vdd_sysfs passed***\n");
-
- /*registering with hwmon class*/
- vinfo->dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(vinfo->dev)) {
- ret = PTR_ERR(vinfo->dev);
- vinfo->dev = NULL;
- dev_dbg(&pdev->dev, "vdd hwmon_dev_regs failed\n");
- goto vdd_error2;
- }
- ret = request_threaded_irq(vinfo->irq, vdd_intrpt_handler,
- vdd_intrptThread_handler,
- IRQF_TRIGGER_FALLING,
- DRIVER_NAME, vinfo);
- if (ret) {
- dev_dbg(&pdev->dev, "vdd request_threaded_irq failed:%d\n",
- ret);
- goto vdd_error2;
- }
-
- /*initialize the timers */
- init_timer(&masking_timer);
- masking_timer.function = timer_platform_ready_tohandle;
- init_timer(&spurious_timer);
- spurious_timer.function = timer_spurious_cleared;
-
- ret = intel_scu_ipc_iowrite8(MBCUIRQ, 0x00);
- if (ret) {
- dev_dbg(&pdev->dev,
- "vdd unmasking%d\n", ret);
- goto vdd_error2;
- }
-
- ret = intel_scu_ipc_update_register(VWARNA_CFG,
- DEBOUNCE | VWARNA_VOLT_THRES, 0xF7);
- if (ret) {
- dev_dbg(&pdev->dev,
- "vdd update VWARNA_CFG debounce time failed:%d\n", ret);
- goto vdd_ok;
- }
-
- ret = intel_scu_ipc_update_register(VWARNB_CFG,
- DEBOUNCE | VWARNB_VOLT_THRES, 0xF7);
- if (ret) {
- dev_dbg(&pdev->dev,
- "vdd updating VWARNB_CFG debounce time failed:%d\n", ret);
- goto vdd_ok;
- }
-
- ret = intel_scu_ipc_update_register(VCRIT_CFG,
- DEBOUNCE | VCRIT_VOLT_THRES, 0xF7);
- if (ret) {
- dev_dbg(&pdev->dev,
- "vdd updating VCRIT_CFG debounce time failed:%d\n", ret);
- goto vdd_ok;
- }
-vdd_ok:
- dev_dbg(&pdev->dev, "***vdd Probe: returning SUCCESS ***\n");
- return 0;
-vdd_error2:
- hwmon_device_unregister(vinfo->dev);
- sysfs_remove_group(&pdev->dev.kobj, &mid_vdd_gr);
-vdd_error1:
- iounmap(vinfo->bcu_stat);
- return ret;
-}
-
-static int mid_vdd_resume(struct device *dev)
-{
- return 0;
-}
-
-static int mid_vdd_suspend(struct device *dev)
-{
- return 0;
-}
-
-static int mid_vdd_remove(struct ipc_device *pdev)
-{
- struct vdd_info *vinfo = ipc_get_drvdata(pdev);
-
- if (vinfo) {
- hwmon_device_unregister(vinfo->dev);
- sysfs_remove_group(&pdev->dev.kobj, &mid_vdd_gr);
- iounmap(vinfo->bcu_stat);
- }
- return 0;
-}
-
-/*********************************************************************
- * Driver initialisation and finalization
- *********************************************************************/
-static const struct ipc_device_id vdd_id_table[] = {
- { DEVICE_NAME, 1 },
- { },
-};
-
-static const struct dev_pm_ops msic_vdd_pm_ops = {
- .suspend = mid_vdd_suspend,
- .resume = mid_vdd_resume,
-};
-
-static struct ipc_driver mid_volt_drop_detect_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .pm = &msic_vdd_pm_ops,
- },
- .probe = mid_vdd_probe,
- .remove = __devexit_p(mid_vdd_remove),
- .id_table = vdd_id_table,
-};
-
-static int __init mid_vdd_module_init(void)
-{
- return ipc_driver_register(&mid_volt_drop_detect_driver);
-}
-
-static void __exit mid_vdd_module_exit(void)
-{
- ipc_driver_unregister(&mid_volt_drop_detect_driver);
-}
-
-module_init(mid_vdd_module_init);
-module_exit(mid_vdd_module_exit);
-
-MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
-MODULE_AUTHOR("Chaurasia, Avinash K <avinash.k.chaurasia@intel.com>");
-MODULE_DESCRIPTION("Intel CloverView Voltage Drop Detection Driver");
-MODULE_LICENSE("GPL");