summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/irqchip/irq-tegra.c
AgeCommit message (Expand)AuthorFilesLines
2016-04-13These changes are the raw update to linux-4.4.6-rt14. Kernel sourcesJosé Pekkarinen1-28/+31
2015-08-04Add the rt linux 4.1.3-rt3 as baseYunhong Jiang1-0/+377
='n85' href='#n85'>85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
/*
 *  MEN 14F021P00 Board Management Controller (BMC) MFD Core Driver.
 *
 *  Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH
 *
 *  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;  either version 2 of the  License, or (at your
 *  option) any later version.
 */

#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>

#define BMC_CMD_WDT_EXIT_PROD	0x18
#define BMC_CMD_WDT_PROD_STAT	0x19
#define BMC_CMD_REV_MAJOR	0x80
#define BMC_CMD_REV_MINOR	0x81
#define BMC_CMD_REV_MAIN	0x82

static struct mfd_cell menf21bmc_cell[] = {
	{ .name = "menf21bmc_wdt", },
	{ .name = "menf21bmc_led", },
	{ .name = "menf21bmc_hwmon", }
};

static int menf21bmc_wdt_exit_prod_mode(struct i2c_client *client)
{
	int val, ret;

	val = i2c_smbus_read_byte_data(client, BMC_CMD_WDT_PROD_STAT);
	if (val < 0)
		return val;

	/*
	 * Production mode should be not active after delivery of the Board.
	 * To be sure we check it, inform the user and exit the mode
	 * if active.
	 */
	if (val == 0x00) {
		dev_info(&client->dev,
			"BMC in production mode. Exit production mode\n");

		ret = i2c_smbus_write_byte(client, BMC_CMD_WDT_EXIT_PROD);
		if (ret < 0)
			return ret;
	}

	return 0;
}

static int
menf21bmc_probe(struct i2c_client *client, const struct i2c_device_id *ids)
{
	int rev_major, rev_minor, rev_main;
	int ret;

	ret = i2c_check_functionality(client->adapter,
				      I2C_FUNC_SMBUS_BYTE_DATA |
				      I2C_FUNC_SMBUS_WORD_DATA |
				      I2C_FUNC_SMBUS_BYTE);
	if (!ret)
		return -ENODEV;

	rev_major = i2c_smbus_read_word_data(client, BMC_CMD_REV_MAJOR);
	if (rev_major < 0) {
		dev_err(&client->dev, "failed to get BMC major revision\n");
		return rev_major;
	}

	rev_minor = i2c_smbus_read_word_data(client, BMC_CMD_REV_MINOR);
	if (rev_minor < 0) {
		dev_err(&client->dev, "failed to get BMC minor revision\n");
		return rev_minor;
	}

	rev_main = i2c_smbus_read_word_data(client, BMC_CMD_REV_MAIN);
	if (rev_main < 0) {
		dev_err(&client->dev, "failed to get BMC main revision\n");
		return rev_main;
	}

	dev_info(&client->dev, "FW Revision: %02d.%02d.%02d\n",
		 rev_major, rev_minor, rev_main);

	/*
	 * We have to exit the Production Mode of the BMC to activate the
	 * Watchdog functionality and the BIOS life sign monitoring.
	 */
	ret = menf21bmc_wdt_exit_prod_mode(client);
	if (ret < 0) {
		dev_err(&client->dev, "failed to leave production mode\n");
		return ret;
	}

	ret = mfd_add_devices(&client->dev, 0, menf21bmc_cell,
			      ARRAY_SIZE(menf21bmc_cell), NULL, 0, NULL);
	if (ret < 0) {
		dev_err(&client->dev, "failed to add BMC sub-devices\n");
		return ret;
	}

	return 0;
}

static int menf21bmc_remove(struct i2c_client *client)
{
	mfd_remove_devices(&client->dev);
	return 0;
}

static const struct i2c_device_id menf21bmc_id_table[] = {
	{ "menf21bmc" },
	{ }
};
MODULE_DEVICE_TABLE(i2c, menf21bmc_id_table);

static struct i2c_driver menf21bmc_driver = {
	.driver.name	= "menf21bmc",
	.id_table	= menf21bmc_id_table,
	.probe		= menf21bmc_probe,
	.remove		= menf21bmc_remove,
};

module_i2c_driver(menf21bmc_driver);

MODULE_DESCRIPTION("MEN 14F021P00 BMC mfd core driver");
MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
MODULE_LICENSE("GPL v2");