162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TI/National Semiconductor LP3943 MFD Core Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2013 Texas Instruments 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Milo Kim <milo.kim@ti.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Driver structure: 1062306a36Sopenharmony_ci * LP3943 is an integrated device capable of driving 16 output channels. 1162306a36Sopenharmony_ci * It can be used for a GPIO expander and PWM generators. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * LED control General usage for a device 1462306a36Sopenharmony_ci * ___________ ____________________________ 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * LP3943 MFD ---- GPIO expander leds-gpio eg) HW enable pin 1762306a36Sopenharmony_ci * | 1862306a36Sopenharmony_ci * --- PWM generator leds-pwm eg) PWM input 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Internal two PWM channels are used for LED dimming effect. 2162306a36Sopenharmony_ci * And each output pin can be used as a GPIO as well. 2262306a36Sopenharmony_ci * The LED functionality can work with GPIOs or PWMs. 2362306a36Sopenharmony_ci * LEDs can be controlled with legacy leds-gpio(static brightness) or 2462306a36Sopenharmony_ci * leds-pwm drivers(dynamic brightness control). 2562306a36Sopenharmony_ci * Alternatively, it can be used for generic GPIO and PWM controller. 2662306a36Sopenharmony_ci * For example, a GPIO is HW enable pin of a device. 2762306a36Sopenharmony_ci * A PWM is input pin of a backlight device. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <linux/err.h> 3162306a36Sopenharmony_ci#include <linux/gpio.h> 3262306a36Sopenharmony_ci#include <linux/i2c.h> 3362306a36Sopenharmony_ci#include <linux/mfd/core.h> 3462306a36Sopenharmony_ci#include <linux/mfd/lp3943.h> 3562306a36Sopenharmony_ci#include <linux/module.h> 3662306a36Sopenharmony_ci#include <linux/of.h> 3762306a36Sopenharmony_ci#include <linux/slab.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define LP3943_MAX_REGISTERS 0x09 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Register configuration for pin MUX */ 4262306a36Sopenharmony_cistatic const struct lp3943_reg_cfg lp3943_mux_cfg[] = { 4362306a36Sopenharmony_ci /* address, mask, shift */ 4462306a36Sopenharmony_ci { LP3943_REG_MUX0, 0x03, 0 }, 4562306a36Sopenharmony_ci { LP3943_REG_MUX0, 0x0C, 2 }, 4662306a36Sopenharmony_ci { LP3943_REG_MUX0, 0x30, 4 }, 4762306a36Sopenharmony_ci { LP3943_REG_MUX0, 0xC0, 6 }, 4862306a36Sopenharmony_ci { LP3943_REG_MUX1, 0x03, 0 }, 4962306a36Sopenharmony_ci { LP3943_REG_MUX1, 0x0C, 2 }, 5062306a36Sopenharmony_ci { LP3943_REG_MUX1, 0x30, 4 }, 5162306a36Sopenharmony_ci { LP3943_REG_MUX1, 0xC0, 6 }, 5262306a36Sopenharmony_ci { LP3943_REG_MUX2, 0x03, 0 }, 5362306a36Sopenharmony_ci { LP3943_REG_MUX2, 0x0C, 2 }, 5462306a36Sopenharmony_ci { LP3943_REG_MUX2, 0x30, 4 }, 5562306a36Sopenharmony_ci { LP3943_REG_MUX2, 0xC0, 6 }, 5662306a36Sopenharmony_ci { LP3943_REG_MUX3, 0x03, 0 }, 5762306a36Sopenharmony_ci { LP3943_REG_MUX3, 0x0C, 2 }, 5862306a36Sopenharmony_ci { LP3943_REG_MUX3, 0x30, 4 }, 5962306a36Sopenharmony_ci { LP3943_REG_MUX3, 0xC0, 6 }, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const struct mfd_cell lp3943_devs[] = { 6362306a36Sopenharmony_ci { 6462306a36Sopenharmony_ci .name = "lp3943-pwm", 6562306a36Sopenharmony_ci .of_compatible = "ti,lp3943-pwm", 6662306a36Sopenharmony_ci }, 6762306a36Sopenharmony_ci { 6862306a36Sopenharmony_ci .name = "lp3943-gpio", 6962306a36Sopenharmony_ci .of_compatible = "ti,lp3943-gpio", 7062306a36Sopenharmony_ci }, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciint lp3943_read_byte(struct lp3943 *lp3943, u8 reg, u8 *read) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci int ret; 7662306a36Sopenharmony_ci unsigned int val; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci ret = regmap_read(lp3943->regmap, reg, &val); 7962306a36Sopenharmony_ci if (ret < 0) 8062306a36Sopenharmony_ci return ret; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci *read = (u8)val; 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lp3943_read_byte); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ciint lp3943_write_byte(struct lp3943 *lp3943, u8 reg, u8 data) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci return regmap_write(lp3943->regmap, reg, data); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lp3943_write_byte); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ciint lp3943_update_bits(struct lp3943 *lp3943, u8 reg, u8 mask, u8 data) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci return regmap_update_bits(lp3943->regmap, reg, mask, data); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lp3943_update_bits); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic const struct regmap_config lp3943_regmap_config = { 10062306a36Sopenharmony_ci .reg_bits = 8, 10162306a36Sopenharmony_ci .val_bits = 8, 10262306a36Sopenharmony_ci .max_register = LP3943_MAX_REGISTERS, 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int lp3943_probe(struct i2c_client *cl) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct lp3943 *lp3943; 10862306a36Sopenharmony_ci struct device *dev = &cl->dev; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci lp3943 = devm_kzalloc(dev, sizeof(*lp3943), GFP_KERNEL); 11162306a36Sopenharmony_ci if (!lp3943) 11262306a36Sopenharmony_ci return -ENOMEM; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci lp3943->regmap = devm_regmap_init_i2c(cl, &lp3943_regmap_config); 11562306a36Sopenharmony_ci if (IS_ERR(lp3943->regmap)) 11662306a36Sopenharmony_ci return PTR_ERR(lp3943->regmap); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci lp3943->pdata = dev_get_platdata(dev); 11962306a36Sopenharmony_ci lp3943->dev = dev; 12062306a36Sopenharmony_ci lp3943->mux_cfg = lp3943_mux_cfg; 12162306a36Sopenharmony_ci i2c_set_clientdata(cl, lp3943); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return devm_mfd_add_devices(dev, -1, lp3943_devs, 12462306a36Sopenharmony_ci ARRAY_SIZE(lp3943_devs), 12562306a36Sopenharmony_ci NULL, 0, NULL); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic const struct i2c_device_id lp3943_ids[] = { 12962306a36Sopenharmony_ci { "lp3943", 0 }, 13062306a36Sopenharmony_ci { } 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lp3943_ids); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci#ifdef CONFIG_OF 13562306a36Sopenharmony_cistatic const struct of_device_id lp3943_of_match[] = { 13662306a36Sopenharmony_ci { .compatible = "ti,lp3943", }, 13762306a36Sopenharmony_ci { } 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, lp3943_of_match); 14062306a36Sopenharmony_ci#endif 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic struct i2c_driver lp3943_driver = { 14362306a36Sopenharmony_ci .probe = lp3943_probe, 14462306a36Sopenharmony_ci .driver = { 14562306a36Sopenharmony_ci .name = "lp3943", 14662306a36Sopenharmony_ci .of_match_table = of_match_ptr(lp3943_of_match), 14762306a36Sopenharmony_ci }, 14862306a36Sopenharmony_ci .id_table = lp3943_ids, 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cimodule_i2c_driver(lp3943_driver); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciMODULE_DESCRIPTION("LP3943 MFD Core Driver"); 15462306a36Sopenharmony_ciMODULE_AUTHOR("Milo Kim"); 15562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 156