diff options
author | Robby Cai <r63905@freescale.com> | 2015-09-16 14:39:16 +0800 |
---|---|---|
committer | Dong Aisheng <aisheng.dong@nxp.com> | 2019-11-25 15:46:05 +0800 |
commit | 16d0d9837ef1cf6ece0c8d8c11fafa44394c566c (patch) | |
tree | 3c215931ef3e4359848d8cebd3c3ea841f31a844 /drivers/mfd | |
parent | baddd4202243410dffff93d9f9dd5daabca814ed (diff) |
MLK-11556-1 pmic: max17135: add hwmon, mfd and regulator drivers for this pmic
Add PMIC 'MAX17135' module drivers to 4.1.y kernel. These are necessary
to supply power for E-ink panel display functions.
Signed-off-by: Robby Cai <r63905@freescale.com>
Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Kconfig | 8 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/max17135-core.c | 270 |
3 files changed, 279 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ae24d3ea68ea..01547046417b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -737,6 +737,14 @@ config MFD_MAX14577 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX17135 + tristate "Maxim MAX17135 EPD PMIC core" + depends on I2C + + help + This is the MAX17135 PMIC support. It includes + core support for communication with the MAX17135 chip. + config MFD_MAX77620 bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support" depends on I2C=y diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index c1067ea46204..96f5c5c262a9 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -158,6 +158,7 @@ obj-$(CONFIG_MFD_DA9063) += da9063.o obj-$(CONFIG_MFD_DA9150) += da9150-core.o obj-$(CONFIG_MFD_MAX14577) += max14577.o +obj-$(CONFIG_MFD_MAX17135) += max17135-core.o obj-$(CONFIG_MFD_MAX77620) += max77620.o obj-$(CONFIG_MFD_MAX77650) += max77650.o obj-$(CONFIG_MFD_MAX77686) += max77686.o diff --git a/drivers/mfd/max17135-core.c b/drivers/mfd/max17135-core.c new file mode 100644 index 000000000000..03773ec6f931 --- /dev/null +++ b/drivers/mfd/max17135-core.c @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2010-2015 Freescale Semiconductor, Inc. + * Copyright 2019 NXP + */ + +/*! + * @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) { + kfree(client); + 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); |