max17135-core.c 6.53 KB
/*
 * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
 *
 * 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.
 *
 * 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
 *
 */

/*!
 * @file pmic/core/max17135.c
 * @brief This file contains MAX17135 specific PMIC code. This implementaion
 * may differ for each PMIC chip.
 *
 * @ingroup PMIC_CORE
 */

/*
 * Includes
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regulator/machine.h>
#include <linux/pmic_status.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max17135.h>
#include <asm/mach-types.h>

static int max17135_detect(struct i2c_client *client,
			  struct i2c_board_info *info);
struct i2c_client *max17135_client;
static struct regulator *gpio_regulator;

static struct mfd_cell max17135_devs[] = {
	{ .name = "max17135-pmic", },
	{ .name = "max17135-sns", },
};

static const unsigned short normal_i2c[] = {0x48, I2C_CLIENT_END};

int max17135_reg_read(int reg_num, unsigned int *reg_val)
{
	int result;

	if (max17135_client == NULL)
		return PMIC_ERROR;

	if ((reg_num == REG_MAX17135_EXT_TEMP) ||
		(reg_num == REG_MAX17135_INT_TEMP)) {
		result = i2c_smbus_read_word_data(max17135_client, reg_num);
		if (result < 0) {
			dev_err(&max17135_client->dev,
				"Unable to read MAX17135 register via I2C\n");
			return PMIC_ERROR;
		}
		/* Swap bytes for dword read */
		result = (result >> 8) | ((result & 0xFF) << 8);
	} else {
		result = i2c_smbus_read_byte_data(max17135_client, reg_num);
		if (result < 0) {
			dev_err(&max17135_client->dev,
				"Unable to read MAX17135 register via I2C\n");
			return PMIC_ERROR;
		}
	}

	*reg_val = result;
	return PMIC_SUCCESS;
}

int max17135_reg_write(int reg_num, const unsigned int reg_val)
{
	int result;

	if (max17135_client == NULL)
		return PMIC_ERROR;

	result = i2c_smbus_write_byte_data(max17135_client, reg_num, reg_val);
	if (result < 0) {
		dev_err(&max17135_client->dev,
			"Unable to write MAX17135 register via I2C\n");
		return PMIC_ERROR;
	}

	return PMIC_SUCCESS;
}

#ifdef CONFIG_OF
static struct max17135_platform_data *max17135_i2c_parse_dt_pdata(
					struct device *dev)
{
	struct max17135_platform_data *pdata;

	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata) {
		dev_err(dev, "could not allocate memory for pdata\n");
		return ERR_PTR(-ENOMEM);
	}

	return pdata;
}
#else
static struct max17135_platform_data *max17135_i2c_parse_dt_pdata(
					struct device *dev)
{
	return NULL;
}
#endif	/* !CONFIG_OF */

static int max17135_probe(struct i2c_client *client,
			    const struct i2c_device_id *id)
{
	struct max17135 *max17135;
	struct max17135_platform_data *pdata = client->dev.platform_data;
	struct device_node *np = client->dev.of_node;
	int ret = 0;

	if (!np)
		return -ENODEV;

	gpio_regulator = devm_regulator_get(&client->dev, "SENSOR");
	if (!IS_ERR(gpio_regulator)) {
		ret = regulator_enable(gpio_regulator);
		if (ret) {
			dev_err(&client->dev, "gpio set voltage error\n");
			return ret;
		}
	}

	/* Create the PMIC data structure */
	max17135 = kzalloc(sizeof(struct max17135), GFP_KERNEL);
	if (max17135 == NULL)
		return -ENOMEM;

	/* Initialize the PMIC data structure */
	i2c_set_clientdata(client, max17135);
	max17135->dev = &client->dev;
	max17135->i2c_client = client;

	max17135_client = client;
	ret = max17135_detect(client, NULL);
	if (ret)
		goto err1;

	mfd_add_devices(max17135->dev, -1, max17135_devs,
			ARRAY_SIZE(max17135_devs),
			NULL, 0, NULL);

	if (max17135->dev->of_node) {
		pdata = max17135_i2c_parse_dt_pdata(max17135->dev);
		if (IS_ERR(pdata)) {
			ret = PTR_ERR(pdata);
			goto err2;
		}

	}
	max17135->pdata = pdata;

	dev_info(&client->dev, "PMIC MAX17135 for eInk display\n");

	return ret;
err2:
	mfd_remove_devices(max17135->dev);
err1:
	kfree(max17135);

	return ret;
}


static int max17135_remove(struct i2c_client *i2c)
{
	struct max17135 *max17135 = i2c_get_clientdata(i2c);

	mfd_remove_devices(max17135->dev);
	return 0;
}

/* Return 0 if detection is successful, -ENODEV otherwise */
static int max17135_detect(struct i2c_client *client,
			  struct i2c_board_info *info)
{
	struct i2c_adapter *adapter = client->adapter;
	u8 chip_rev, chip_id;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
		return -ENODEV;

	/* detection */
	if (i2c_smbus_read_byte_data(client,
		REG_MAX17135_PRODUCT_REV) != 0) {
		dev_err(&adapter->dev,
			"Max17135 PMIC not found!\n");
		return -ENODEV;
	}

	/* identification */
	chip_rev = i2c_smbus_read_byte_data(client,
		 REG_MAX17135_PRODUCT_REV);
	chip_id = i2c_smbus_read_byte_data(client,
		  REG_MAX17135_PRODUCT_ID);

	if (chip_rev != 0x00 || chip_id != 0x4D) { /* identification failed */
		dev_info(&adapter->dev,
		    "Unsupported chip (man_id=0x%02X, "
		    "chip_id=0x%02X).\n", chip_rev, chip_id);
		return -ENODEV;
	}

	if (info)
		strlcpy(info->type, "max17135_sensor", I2C_NAME_SIZE);

	return 0;
}

static const struct i2c_device_id max17135_id[] = {
       { "max17135", 0 },
       { }
};
MODULE_DEVICE_TABLE(i2c, max17135_id);

static const struct of_device_id max17135_dt_ids[] = {
	{
		.compatible = "maxim,max17135",
		.data = (void *) &max17135_id[0],
	}, {
		/* sentinel */
	}
};
MODULE_DEVICE_TABLE(of, max17135_dt_ids);


static struct i2c_driver max17135_driver = {
	.driver = {
		   .name = "max17135",
		   .owner = THIS_MODULE,
		   .of_match_table = max17135_dt_ids,
	},
	.probe = max17135_probe,
	.remove = max17135_remove,
	.id_table = max17135_id,
	.detect = max17135_detect,
	.address_list = &normal_i2c[0],
};

static int __init max17135_init(void)
{
	return i2c_add_driver(&max17135_driver);
}

static void __exit max17135_exit(void)
{
	i2c_del_driver(&max17135_driver);
}

/*
 * Module entry points
 */
subsys_initcall(max17135_init);
module_exit(max17135_exit);