设备树
&i2c0 {
mps2022_cam_pp: pp@21 {
reg = <0x21>;
compatible = "mps,mps2022";
device-supply = <&_3v3_db_ivi>;
camera-supply = <&_8v_cam>;
/* power down bit of mps2022 */
gpio = <&gpio6 12 GPIO_ACTIVE_HIGH>;
/* parent IRQ is gpio6 31 */
interrupt-parent = <&gpio6>;
interrupts = <31 IRQ_TYPE_EDGE_BOTH>;
status = "disabled";
regulators {
cam1_regulator: output1 {
regulator-name = "cam1";
};
cam2_regulator: output2 {
regulator-name = "cam2";
};
};
};
};
&xxx_x_des {
#address-cells = <1>;
#size-cells = <0>;
poc-supply = <&cam2_regulator>;
};
驱动源代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#ifdef CONFIG_DIAG_CLASS
#include <linux/diagnostic.h>
#include <linux/diagnostic/diagnostic_mps2022.h>
#include <linux/wait.h>
#endif /* CONFIG_DIAG_CLASS */
#define MPS2022_OUTPUT_COUNT (3)
/* MPS2022_REG_MASK */
#define MPS2022_MASK_OVTST_BIT (BIT(7))
#define MPS2022_MASK_ACCM_BIT (BIT(6))
#define MPS2022_MASK_TSM_BIT (BIT(5))
#define MPS2022_MASK_VDDM_BIT (BIT(4))
#define MPS2022_MASK_VINM_BIT (BIT(3))
#define MPS2022_MASK_OCM_BIT (BIT(2))
#define MPS2022_MASK_OVM_BIT (BIT(1))
#define MPS2022_MASK_UVM_BIT (BIT(0))
/* MPS2022_REG_CONFIG */
#define MPS2022_CONFIG_ENC_BIT (BIT(5))
#define MPS2022_CONFIG_CLR_BIT (BIT(4))
#define MPS2022_CONFIG_EN3_BIT (BIT(3))
#define MPS2022_CONFIG_EN2_BIT (BIT(2))
#define MPS2022_CONFIG_EN1_BIT (BIT(1))
#define MPS2022_CONFIG_EN0_BIT (BIT(0))
#define MPS2022_CONFIG_EN_BITS (MPS2022_CONFIG_EN3_BIT | \
MPS2022_CONFIG_EN2_BIT | \
MPS2022_CONFIG_EN1_BIT | \
MPS2022_CONFIG_EN0_BIT)
/* MPS2022_REG_ID */
#define MPS2022_ID_BITS (BIT(5) | BIT(4))
#define MPS2022_ID_SHIFT (4)
#define MPS2022_REVISION_BITS (BIT(3) | BIT(2) | BIT(1) | BIT(0))
/* MPS2022_REG_STAT1 */
#define MPS2022_STAT1_ISET_BIT (BIT(5))
#define MPS2022_STAT1_ACC_BIT (BIT(4))
#define MPS2022_STAT1_OVIN_BIT (BIT(3))
#define MPS2022_STAT1_UVIN_BIT (BIT(2))
#define MPS2022_STAT1_OVDD_BIT (BIT(1))
#define MPS2022_STAT1_UVDD_BIT (BIT(0))
/* MPS2022_REG_STAT2 */
#define MPS2022_STAT2_COUNT (4)
#define MPS2022_STAT2_TS_BIT (BIT(3))
#define MPS2022_STAT2_OC_BIT (BIT(2))
#define MPS2022_STAT2_OV_BIT (BIT(1))
#define MPS2022_STAT2_UV_BIT (BIT(0))
/* Registers */
enum {
MPS2022_REG_DEV_REV = 0,
MPS2022_REG_DEV_STAT,
MPS2022_REG_ERR_FLAG1,
MPS2022_REG_ERR_FLAG2,
MPS2022_REG_DEV_CTRL,
MPS2022_REG_MON_VOUT1,
MPS2022_REG_MON_VOUT2,
MPS2022_REG_MON_IOUT1,
MPS2022_REG_MON_IOUT2,
MPS2022_REG_SET_VOUT1,
MPS2022_REG_SET_VOUT2,
MPS2022_REG_SET_VPREBOOST,
MPS2022_REG_SET_VPREBOOST_ON,
MPS2022_REG_SET_PG_UVOV,
MPS2022_REG_SET_IOUT_LIM1,
MPS2022_REG_SET_IOUT_LIM2,
};
struct mps2022_output {
struct regulator_desc desc;
struct regulator_dev *dev;
struct device_node *np;
const char *supply_name;
bool enabled;
bool exist;
};
struct mps2022_config {
struct gpio_desc *en_gpio;
struct regulator *vdd;
struct regulator *vin;
struct mps2022_output outputs[MPS2022_OUTPUT_COUNT];
};
struct mps2022_data {
struct i2c_client *client;
struct device *dev;
struct regmap *regmap;
struct mps2022_config *config;
int id;
irq_handler_t irq_thread;
unsigned long irqflags;
#ifdef CONFIG_DIAG_CLASS
uint32_t diag_status;
uint32_t adc_status;
struct diag_classdev diag_cdev;
struct mutex diag_lock;
wait_queue_head_t adc_queue;
bool adc_done;
#endif /* CONFIG_DIAG_CLASS */
};
static const struct regmap_config mps2022_regmap = {
.reg_bits = 8,
.val_bits = 16,
.max_register = 0x0f,
};
const char* mps2022_id[] = {
"MPS2022",
};
static unsigned char mps2022_crc8_pec_check(unsigned char* ptr,unsigned char len)
{
unsigned char i;
static const unsigned char crcpoly = 0x07;
unsigned char crc = 0x00;
while(len--)
{
crc ^= *ptr++;
for (i=8; i>0; --i)
{
if (crc & 0x80)
crc = (crc << 1) ^ crcpoly;
else
crc = (crc << 1);
}
}
return crc;
}
/**
* mps2022_regmap_read() - Read a value from a single register
*
* @map: Register map to read from
* @reg: Register to be read from
* @val: Pointer to store read value
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
static int mps2022_regmap_read(struct mps2022_data *mps2022, unsigned int reg, unsigned int *val)
{
unsigned char data_ptr[4]={0x42,0,0x43,0};
unsigned char pec_data;
unsigned char crc,retry_cnt=0;
int ret = 0;
data_ptr[1] = reg;
retry:
ret = regmap_read(mps2022->regmap, reg, val);
if (ret < 0) {
dev_err( mps2022->dev,"Failed to read mps2022 reg[0x%x] value[0x%x]\n", reg,*val);
return ret;
}
pec_data = *val & 0xff;
*val = (*val >> 8) & 0xff;
data_ptr[3] = *val;
crc = mps2022_crc8_pec_check(data_ptr,sizeof(data_ptr));
/* PEC data check, if check failed then retry 3 times */
if( crc != pec_data ){
if(retry_cnt<3){
retry_cnt++;
goto retry;
}else{
dev_err( mps2022->dev,"The PEC data is mismatch when reading mps2022 reg[0x%x]\n", reg);
return -1;
}
}
return ret;
}
/**
* mps2022_regmap_write() - Write a value to a single register
*
* @map: Register map to write to
* @reg: Register to write to
* @val: Value to be written
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.
*/
static int mps2022_regmap_write(struct mps2022_data *mps2022, unsigned int reg, unsigned int val)
{
unsigned char data_ptr[3]={0x42,0,0};
unsigned int pec_data;
unsigned char crc;
int ret = 0;
data_ptr[1] = reg;
data_ptr[2] = val;
crc = mps2022_crc8_pec_check(data_ptr,sizeof(data_ptr));
pec_data = (val << 8) | crc;
ret = regmap_write(mps2022->regmap,reg,pec_data);
if (ret < 0) {
dev_err(mps2022->dev, "Failed to write mps2022 reg[0x%x] value[0x%x]\n", reg,val);
return ret;
}
return ret;
}
static int mps2022_find_which_output(struct regulator_dev *rdev,
struct mps2022_data *mps2022)
{
int i;
for (i = 0; i < MPS2022_OUTPUT_COUNT; i++) {
if (rdev == mps2022->config->outputs[i].dev)
return i;
}
dev_err(mps2022->dev, "Regulator is not valid\n");
return -EINVAL;
}
static int mps2022_is_enabled(struct regulator_dev *rdev)
{
struct mps2022_data *mps2022 = rdev_get_drvdata(rdev);
int i;
i = mps2022_find_which_output(rdev, mps2022);
if (i < 0)
return i;
return mps2022->config->outputs[i].enabled;
}
static int mps2022_set_output(struct mps2022_data *mps2022, int num,
bool state)
{
int ret = 0;
unsigned int val = 0;
ret = mps2022_regmap_read(mps2022,MPS2022_REG_DEV_CTRL,&val);
if (ret < 0) {
dev_err(mps2022->dev, "Failed to read register 0x%x: 0x%x\n",
MPS2022_REG_DEV_CTRL, ret);
return ret;
}
/* enable/disable LDO output */
if(state){
ret = mps2022_regmap_write(mps2022, MPS2022_REG_DEV_CTRL,val |(1 << (6-num)));
dev_info(mps2022->dev, "Enabe LDO%d output\n",num+1);
}else{
ret = mps2022_regmap_write(mps2022, MPS2022_REG_DEV_CTRL,val &~(1 << (6-num)));
dev_info(mps2022->dev, "Disable LDO%d output\n",num+1);
}
if (ret < 0) {
dev_err(mps2022->dev, "Failed to update register 0x%x: 0x%x\n",
MPS2022_REG_DEV_CTRL, ret);
return ret;
}
mps2022->config->outputs[num].enabled = state;
return 0;
}
static int mps2022_enable(struct regulator_dev *rdev)
{
struct mps2022_data *mps2022 = rdev_get_drvdata(rdev);
int i;
i = mps2022_find_which_output(rdev, mps2022);
if (i < 0)
return i;
return mps2022_set_output(mps2022, i, true);
}
static int mps2022_disable(struct regulator_dev *rdev)
{
struct mps2022_data *mps2022 = rdev_get_drvdata(rdev);
int i;
i = mps2022_find_which_output(rdev, mps2022);
if (i < 0)
return i;
return mps2022_set_output(mps2022, i, false);
}
static struct regulator_ops mps2022_regulator_ops = {
.enable = mps2022_enable,
.disable = mps2022_disable,
.is_enabled = mps2022_is_enabled,
};
/* mps2022_config_output: Configure output regulators */
static int mps2022_config_output(struct mps2022_data *mps2022,
struct device_node *output_np)
{
struct device *dev = mps2022->dev;
struct mps2022_config *config = mps2022->config;
struct regulator_init_data *init_data;
struct regulator_config reg_cfg = { };
int i, ret;
sscanf(output_np->name, "output%d", &i);
if (i > MPS2022_OUTPUT_COUNT) {
dev_err(dev, "Output node named %s is not valid\n",
output_np->name);
return -EINVAL;
}
/* real output number (1-3) to array output number (0-2) */
i = i - 1;
if (config->outputs[i].exist == true) {
dev_err(dev, "Output node named %s is duplicated\n",
output_np->name);
return -EINVAL;
}
config->outputs[i].exist = true;
if (of_find_property(output_np, "default-state-on", NULL))
config->outputs[i].enabled = true;
else
config->outputs[i].enabled = false;
config->outputs[i].np = output_np;
init_data = of_get_regulator_init_data(dev, output_np,
&config->outputs[i].desc);
if (!init_data) {
dev_err(dev, "Failed to allocate regulator init data\n");
return -ENOMEM;
}
config->outputs[i].supply_name = init_data->constraints.name;
config->outputs[i].desc.name =
devm_kstrdup(dev, config->outputs[i].supply_name, GFP_KERNEL);
if (config->outputs[i].desc.name == NULL) {
dev_err(dev, "Failed to allocate supply name\n");
return -ENOMEM;
}
config->outputs[i].desc.type = REGULATOR_VOLTAGE;
config->outputs[i].desc.owner = THIS_MODULE;
config->outputs[i].desc.ops = &mps2022_regulator_ops;
reg_cfg.dev = dev;
reg_cfg.init_data = init_data;
reg_cfg.driver_data = mps2022;
reg_cfg.of_node = output_np;
config->outputs[i].dev = devm_regulator_register(dev,
&config->outputs[i].desc, ®_cfg);
if (IS_ERR(config->outputs[i].dev)) {
ret = PTR_ERR(config->outputs[i].dev);
dev_err(dev, "Failed to register regulator: %d\n", ret);
return ret;
}
dev_dbg(dev, "Output node named %s found\n", output_np->name);
return 0;
}
static int mps2022_set_output_default(struct mps2022_data *mps2022,int num)
{
int ret = 0;
ret = mps2022_regmap_write(mps2022, MPS2022_REG_SET_VOUT1+num,0x63);
if (ret < 0) {
dev_err(mps2022->dev, "Failed to update register 0x%x: 0x%x\n",
MPS2022_REG_SET_VOUT1+num, ret);
return ret;
}
dev_info(mps2022->dev, "Set LDO%d as default output\n",num+1);
return ret;
}
/*
* of_get_mps2022_config - extract mps2022_config structure info
* @dev: device requesting for mps2022_config
*
* Populates mps2022_config structure by extracting drvdata from
* device tree node, returns a pointer to the populated structure
*/
static struct mps2022_config * of_get_mps2022_config(
struct mps2022_data *mps2022)
{
struct device *dev = mps2022->dev;
struct mps2022_config *config;
struct device_node *regulators_np, *regulator_child;
int ret, i = 0;
config = devm_kzalloc(dev, sizeof(struct mps2022_config), GFP_KERNEL);
if (!config)
return ERR_PTR(-ENOMEM);
mps2022->config = config;
config->vdd = devm_regulator_get(dev, "device");
if (IS_ERR(config->vdd)) {
ret = PTR_ERR(config->vdd);
dev_err(dev,
"cannot find correct \"device-supply\" parameter: %d\n",
ret);
return ERR_PTR(ret);
}
config->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
if (IS_ERR(config->en_gpio)) {
ret = PTR_ERR(config->en_gpio);
dev_err(dev, "failed to get enable gpio: %d", ret);
return ERR_PTR(ret);
}
config->vin = devm_regulator_get(dev, "camera");
if (IS_ERR(config->vin)) {
ret = PTR_ERR(config->vin);
dev_err(dev,
"cannot find correct \"camera-supply\" parameter: %d\n",
ret);
return ERR_PTR(ret);
}
msleep(100);
regulators_np = of_get_child_by_name(dev->of_node, "regulators");
if (!regulators_np) {
dev_err(dev,
"cannot find correct \"regulators\" node point\n");
return ERR_PTR(-EINVAL);
}
for (i = 0; i < MPS2022_OUTPUT_COUNT; i++) {
config->outputs[i].exist = false;
}
i = 0;
for_each_child_of_node(regulators_np, regulator_child) {
if (i >= MPS2022_OUTPUT_COUNT) {
dev_err(dev, "too much output regulators provided\n");
return ERR_PTR(-EINVAL);
}
ret = mps2022_config_output(mps2022, regulator_child);
if (ret < 0)
return ERR_PTR(ret);
mps2022_set_output_default(mps2022,i);
if (ret < 0)
return ERR_PTR(ret);
ret = mps2022_set_output(mps2022, i,
config->outputs[i].enabled);
if (ret < 0)
return ERR_PTR(ret);
i++;
}
return config;
}
static int mps2022_diag_inputs(struct mps2022_data *mps2022)
{
int ret;
uint8_t status;
#ifdef CONFIG_DIAG_CLASS
uint32_t adc_res;
#endif /* CONFIG_DIAG_CLASS */
ret = regmap_read(mps2022->regmap, MPS2022_REG_ERR_FLAG1,
(unsigned int *)&status);
if (ret < 0) {
dev_err(mps2022->dev, "Failed to read stat1: %d\n", ret);
return ret;
}
if (status & MPS2022_STAT1_ISET_BIT)
dev_warn(mps2022->dev, "ISET pin open or shorted\n");
if (status & MPS2022_STAT1_ACC_BIT) {
dev_dbg(mps2022->dev, "ADC conversions completed\n");
#ifdef CONFIG_DIAG_CLASS
/* read adc results */
ret = regmap_bulk_read(mps2022->regmap, MPS2022_REG_ERR_FLAG1,
&adc_res, MPS2022_OUTPUT_COUNT);
if (ret < 0) {
dev_err(mps2022->dev,
"fail to read adc registers: %d\n", ret);
return ret;
}
mutex_lock(&mps2022->diag_lock);
mps2022->adc_status = adc_res;
mps2022->adc_done = true;
mutex_unlock(&mps2022->diag_lock);
/* waking up adc_conversion_show function */
wake_up(&mps2022->adc_queue);
#endif /* CONFIG_DIAG_CLASS */
/*
* masking this bit
* it is not relevant to inform user that adc conversion is
* complete while he is already waiting for the conversion
* result through adc_conversion file
*/
status &= ~MPS2022_STAT1_ACC_BIT;
}
if (status & MPS2022_STAT1_OVIN_BIT)
dev_warn(mps2022->dev, "VIN > 16.5V, outputs off\n");
if (status & MPS2022_STAT1_UVIN_BIT)
dev_warn(mps2022->dev, "VIN 鈮?2.7V, outputs off\n");
if (status & MPS2022_STAT1_OVDD_BIT)
dev_warn(mps2022->dev, "VDD > 5.7V, outputs off\n");
if (status & MPS2022_STAT1_UVDD_BIT)
dev_warn(mps2022->dev, "VDD 鈮?2.7V, outputs off\n");
return (int)status;
}
static int mps2022_diag_outputs(struct mps2022_data *mps2022)
{
int ret, i;
uint16_t status;
ret = regmap_bulk_read(mps2022->regmap, MPS2022_REG_ERR_FLAG1,
(unsigned int *)&status, 2);
if (ret < 0) {
dev_err(mps2022->dev, "fail to read stat2: %d\n", ret);
return ret;
}
/*
* i + 1 inside loop is meant to convert array output number (0-3) to
* real output number (1-4)
*/
for (i = 0; i < MPS2022_OUTPUT_COUNT; i++) {
if (status & (MPS2022_STAT2_TS_BIT <<
(i*MPS2022_STAT2_COUNT)))
dev_warn(mps2022->dev,
"Channel %d in thermal shutdown\n", i + 1);
if (status & (MPS2022_STAT2_OC_BIT <<
(i*MPS2022_STAT2_COUNT)))
dev_warn(mps2022->dev,
"Channel %d in current limit (short-to-ground)\n",
i + 1);
if (status & (MPS2022_STAT2_OV_BIT <<
(i*MPS2022_STAT2_COUNT)))
dev_warn(mps2022->dev,
"Channel %d voltage is higher than the input voltage (short-to-battery)\n",
i + 1);
if (status & (MPS2022_STAT2_UV_BIT <<
(i*MPS2022_STAT2_COUNT))) {
/*
* masking this bit when the corresponding channel is
* not enabled
*/
if ((!mps2022->config->outputs[i].enabled)) {
status &= ~(MPS2022_STAT2_UV_BIT <<
(i*MPS2022_STAT2_COUNT));
} else {
dev_warn(mps2022->dev,
"Channel %d undervoltage (shorted output or thermal shutdown)\n",
i + 1);
}
}
}
return (int)status;
}
static irqreturn_t mps2022_irq_thread(int irq, void *data)
{
struct mps2022_data *mps2022 = data;
int ret;
#ifdef CONFIG_DIAG_CLASS
uint32_t diag_status;
#endif /* CONFIG_DIAG_CLASS */
dev_dbg(mps2022->dev, "IRQ caught\n");
ret = mps2022_diag_inputs(mps2022);
if (ret < 0)
goto fail;
#ifdef CONFIG_DIAG_CLASS
diag_status = ret & MPS2022_DIAGNOSTIC_INPUT_MASK;
#endif /* CONFIG_DIAG_CLASS */
ret = mps2022_diag_outputs(mps2022);
if (ret < 0)
goto fail;
#ifdef CONFIG_DIAG_CLASS
diag_status |= (ret & MPS2022_DIAGNOSTIC_OUTPUT_MASK) <<
MPS2022_DIAGNOSTIC_OUTPUT_SHIFT;
/* notify user space if there is an issue */
// if (diag_status) {
mutex_lock(&mps2022->diag_lock);
mps2022->diag_status = diag_status;
mutex_unlock(&mps2022->diag_lock);
diag_monitoring_notify(&mps2022->diag_cdev);
// }
#endif /* CONFIG_DIAG_CLASS */
fail:
return IRQ_HANDLED;
}
#ifdef CONFIG_DIAG_CLASS
int mps2022_sysfs_get_diag_status(struct diag_classdev *diag_cdev)
{
struct mps2022_data *mps2022 =
container_of(diag_cdev, struct mps2022_data, diag_cdev);
uint32_t ret;
mutex_lock(&mps2022->diag_lock);
ret = mps2022->diag_status;
// mps2022->diag_status = 0;
mutex_unlock(&mps2022->diag_lock);
return ret;
}
static ssize_t adc_conversion_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mps2022_data *mps2022 = dev_get_drvdata(dev->parent);
uint32_t ret;
unsigned int val;
/* to start adc conversion */
ret = regmap_read(mps2022->regmap, MPS2022_REG_MON_VOUT1, &val);
if (ret < 0) {
dev_err(mps2022->dev, "Failed to read adc1: %d\n", ret);
return ret;
}
/* wait for adc conversion to be done */
wait_event_timeout(mps2022->adc_queue,
mps2022->adc_done == true,
msecs_to_jiffies(1000));
mps2022->adc_done = false;
mutex_lock(&mps2022->diag_lock);
ret = mps2022->adc_status;
mps2022->adc_status = 0;
mutex_unlock(&mps2022->diag_lock);
return sprintf(buf, "0x%08x\n", ret);
}
static DEVICE_ATTR_RO(adc_conversion);
static struct attribute *mps2022_attr[] = {
&dev_attr_adc_conversion.attr,
NULL
};
static struct attribute_group mps2022_attr_grp = {
.attrs = mps2022_attr,
};
static const struct attribute_group *mps2022_attr_groups[] = {
&mps2022_attr_grp,
NULL,
};
#endif /* CONFIG_DIAG_CLASS */
static int mps2022_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mps2022_data *mps2022;
struct resource *res;
int ret;
mps2022 = devm_kzalloc(&client->dev, sizeof(*mps2022), GFP_KERNEL);
if (!mps2022) {
ret = -ENOMEM;
goto fail;
}
i2c_set_clientdata(client, mps2022);
mps2022->dev = &client->dev;
mps2022->regmap = devm_regmap_init_i2c(client, &mps2022_regmap);
if (IS_ERR(mps2022->regmap)) {
ret = PTR_ERR(mps2022->regmap);
dev_err(&client->dev, "failed to allocate register map: %d\n",
ret);
goto fail;
}
if (!mps2022->dev->of_node) {
ret = -EINVAL;
dev_err(&client->dev, "no of_node found: %d\n", ret);
goto fail;
}
mps2022->config = of_get_mps2022_config(mps2022);
if (IS_ERR(mps2022->config)) {
ret = PTR_ERR(mps2022->config);
goto fail;
}
if (!regulator_is_enabled(mps2022->config->vin)) {
ret = regulator_enable(mps2022->config->vin);
if (ret)
goto fail;
}
if (!regulator_is_enabled(mps2022->config->vdd))
ret = regulator_enable(mps2022->config->vdd);
/* prepare IRQ */
mps2022->irq_thread = &mps2022_irq_thread;
mps2022->irqflags = IRQF_ONESHOT;
#ifdef CONFIG_DIAG_CLASS
init_waitqueue_head(&mps2022->adc_queue);
mps2022->adc_done = false;
mps2022->diag_cdev.groups = mps2022_attr_groups;
mps2022->diag_cdev.get_diag_status = mps2022_sysfs_get_diag_status;
ret = devm_of_diag_classdev_register(mps2022->dev,
mps2022->dev->of_node,
&mps2022->diag_cdev);
if (ret)
goto fail;
mutex_init(&mps2022->diag_lock);
#endif /* CONFIG_DIAG_CLASS */
res = devm_kzalloc(&client->dev, sizeof(struct resource), GFP_KERNEL);
if (!res) {
dev_err(mps2022->dev, "fail to request IRQ resource!!!\n");
ret = -ENOMEM;
goto fail;
}
/* if IRQ well defined in DT, then proceed IRQ configuration */
if (mps2022->irq_thread && client->irq) {
of_irq_to_resource(client->dev.of_node, 0, res);
ret = devm_request_threaded_irq(mps2022->dev,
client->irq, NULL,
mps2022->irq_thread,
mps2022->irqflags |res->flags,
client->name,
i2c_get_clientdata(client));
if (ret) {
dev_err(mps2022->dev, "fail to request IRQ\n");
goto fail;
}
dev_info(mps2022->dev, "IRQ setup done\n");
} else {
dev_info(mps2022->dev, "IRQ setup not done\n");
}
fail:
return ret;
}
static int mps2022_remove(struct i2c_client *client)
{
struct mps2022_data *mps2022 = client->dev.driver_data;
int i;
for (i = 0; i < MPS2022_OUTPUT_COUNT; i++) {
if (mps2022->config->outputs[i].exist) {
if (mps2022_is_enabled(
mps2022->config->outputs[i].dev))
mps2022_disable(
mps2022->config->outputs[i].dev);
}
}
#ifdef CONFIG_DIAG_CLASS
mutex_destroy(&mps2022->diag_lock);
#endif /* CONFIG_DIAG_CLASS */
return 0;
}
static const struct of_device_id mps2022_dt_ids[] = {
{ .compatible = "mps,mps2022" },
{},
};
MODULE_DEVICE_TABLE(of, mps2022_dt_ids);
static const struct i2c_device_id mps2022_i2c_ids[] = {
{ "mps2022", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, mps2022_i2c_ids);
static struct i2c_driver mps2022_driver = {
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
.of_match_table = mps2022_dt_ids,
},
.probe = mps2022_probe,
.remove = mps2022_remove,
.id_table = mps2022_i2c_ids,
};
module_i2c_driver(mps2022_driver);
MODULE_DESCRIPTION("mps Camera Power Protectors driver");
MODULE_AUTHOR("zhenggp");
MODULE_LICENSE("GPL");