mirror of
https://github.com/torvalds/linux.git
synced 2024-10-30 16:51:45 +00:00
Update extcon for v3.16
This patchset add resource-managed functions to automatically control the memory and unregistration operation of extcon. Also, This series support new MAX77836 extcon device driver on existing MAX14577 device because existed a little difference between MAX77836 and MAX14577. Finally, Fix minor issue of extcon driver. Detailed description for patchset: 1. Add resource-managed functions - Add resource-managed functions to automatically free the memory of extcon structure and to control unregistration behavior as following. This new devm_* functions applied all of extcon drivers in drivers/extcon/. : devm_extcon_dev_register/unregister() : devm_extcon_dev_allocate/free() : extcon_dev_allocate/free() for devm_extcon_dev_allocate/free() 2. Add new MAX77836 extcon device - Support MAX77836 device on existing MAX14577 device driver using different compatible string. This patchset has dependency on MFD/ Regulator/Extcon. So, Lee Jones(MFD Maintainer) created Immutable branch between MFD and Extcon due for v3.16 merge-window and then I merged this patchset from MFD git repo[1] to Extcon git repo. : [1] git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd (branch: ib-mfd-extcon-3.16) 3. Fix minor issue of extcon driver - extcon-palmas driver : Fix issue of extcon device name for probe - extcon-max14577 : Fix probe failure about handling wrong return value. : Properly Handle return value of regmap_irq_get_virq function. - extcon-max8997/max77693 driver : Fix NULL pointer exception on missing pdata 4. Code clean for extcon driver - extcon-max8997/max77693 : Use power efficient workqueue for delayed cable detection -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJTepzmAAoJEJzN3yze689TSHMP/2l/pzI1IVqEQIzDnf6ga9AT rHo7kdLya+TxLBggasj21N9jprI3145bkWBL00EcnZkqrav7ctnU71347u7wkMzg pREYwK0OZAeF33rjbCrCPVrUL55XuTzipf4phtcKDSxmbFh/OdRZe4/vOEo0mBxE kTKb0zaePz0jeCur/ajxnZ1E/2DkKTsvUyiYSUYQ1FAjY4RvKkW/3qDYXqMetoYZ 7sJdH5cpbsdGdQj74axuFWqvnINH1i9LY2gGw30tLKa7D15r72wBfA9HuRB/P5XB prvVb19wYLgkfxevZenvDjmyqeMUkFnk2a25Ntd3xndeaBJSCIM9y9tXxtz/fWyq ZPgsE0ma/E2PkKt4c4/mg1BzAGyL8lXU0SEivp03iLV3ByK2rmug7NdwG0Tw0/iE rcx3cdr7QvK4wSgaOt2Hcv+QLqXDZ7onrt3fhx+eHyD5X1ThRCCKbdr+H08eWnqw zGJQ6Ru4nrzZ1NS8bJuAjpKLfWwEWhN1QwvJ/Aw13yP/CIRtWgik+m1cUVTZriJL rlcdKJHbs8lGw07oROurmcEcKCBdr8HDZ4Ajht4qv7LQnYZK4q1N7xbbaI1tqTjb CawoA2ZfZMjNPkt97wwYselL2eRHVEHg5AwhzhVVPzbf/GxGU3GR2NLUeJBzbTaQ TtZbRo8l8GRGT5dGp86J =7wRd -----END PGP SIGNATURE----- Merge tag 'extcon-next-for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon into char-misc-next Chanwoo writes: Update extcon for v3.16 This patchset add resource-managed functions to automatically control the memory and unregistration operation of extcon. Also, This series support new MAX77836 extcon device driver on existing MAX14577 device because existed a little difference between MAX77836 and MAX14577. Finally, Fix minor issue of extcon driver. Detailed description for patchset: 1. Add resource-managed functions - Add resource-managed functions to automatically free the memory of extcon structure and to control unregistration behavior as following. This new devm_* functions applied all of extcon drivers in drivers/extcon/. : devm_extcon_dev_register/unregister() : devm_extcon_dev_allocate/free() : extcon_dev_allocate/free() for devm_extcon_dev_allocate/free() 2. Add new MAX77836 extcon device - Support MAX77836 device on existing MAX14577 device driver using different compatible string. This patchset has dependency on MFD/ Regulator/Extcon. So, Lee Jones(MFD Maintainer) created Immutable branch between MFD and Extcon due for v3.16 merge-window and then I merged this patchset from MFD git repo[1] to Extcon git repo. : [1] git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd (branch: ib-mfd-extcon-3.16) 3. Fix minor issue of extcon driver - extcon-palmas driver : Fix issue of extcon device name for probe - extcon-max14577 : Fix probe failure about handling wrong return value. : Properly Handle return value of regmap_irq_get_virq function. - extcon-max8997/max77693 driver : Fix NULL pointer exception on missing pdata 4. Code clean for extcon driver - extcon-max8997/max77693 : Use power efficient workqueue for delayed cable detection
This commit is contained in:
commit
6a57bad6e7
@ -28,13 +28,13 @@ config EXTCON_ADC_JACK
|
||||
Say Y here to enable extcon device driver based on ADC values.
|
||||
|
||||
config EXTCON_MAX14577
|
||||
tristate "MAX14577 EXTCON Support"
|
||||
tristate "MAX14577/77836 EXTCON Support"
|
||||
depends on MFD_MAX14577
|
||||
select IRQ_DOMAIN
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the MUIC device of
|
||||
Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory
|
||||
Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory
|
||||
detector and switch.
|
||||
|
||||
config EXTCON_MAX77693
|
||||
|
@ -39,7 +39,7 @@
|
||||
* @chan: iio channel being queried.
|
||||
*/
|
||||
struct adc_jack_data {
|
||||
struct extcon_dev edev;
|
||||
struct extcon_dev *edev;
|
||||
|
||||
const char **cable_names;
|
||||
int num_cables;
|
||||
@ -64,7 +64,7 @@ static void adc_jack_handler(struct work_struct *work)
|
||||
|
||||
ret = iio_read_channel_raw(data->chan, &adc_val);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->edev.dev, "read channel() error: %d\n", ret);
|
||||
dev_err(&data->edev->dev, "read channel() error: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ static void adc_jack_handler(struct work_struct *work)
|
||||
}
|
||||
/* if no def has met, it means state = 0 (no cables attached) */
|
||||
|
||||
extcon_set_state(&data->edev, state);
|
||||
extcon_set_state(data->edev, state);
|
||||
}
|
||||
|
||||
static irqreturn_t adc_jack_irq_thread(int irq, void *_data)
|
||||
@ -102,33 +102,33 @@ static int adc_jack_probe(struct platform_device *pdev)
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->edev.name = pdata->name;
|
||||
|
||||
if (!pdata->cable_names) {
|
||||
err = -EINVAL;
|
||||
dev_err(&pdev->dev, "error: cable_names not defined.\n");
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->edev.dev.parent = &pdev->dev;
|
||||
data->edev.supported_cable = pdata->cable_names;
|
||||
data->edev = devm_extcon_dev_allocate(&pdev->dev, pdata->cable_names);
|
||||
if (IS_ERR(data->edev)) {
|
||||
dev_err(&pdev->dev, "failed to allocate extcon device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
data->edev->dev.parent = &pdev->dev;
|
||||
data->edev->name = pdata->name;
|
||||
|
||||
/* Check the length of array and set num_cables */
|
||||
for (i = 0; data->edev.supported_cable[i]; i++)
|
||||
for (i = 0; data->edev->supported_cable[i]; i++)
|
||||
;
|
||||
if (i == 0 || i > SUPPORTED_CABLE_MAX) {
|
||||
err = -EINVAL;
|
||||
dev_err(&pdev->dev, "error: pdata->cable_names size = %d\n",
|
||||
i - 1);
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
data->num_cables = i;
|
||||
|
||||
if (!pdata->adc_conditions ||
|
||||
!pdata->adc_conditions[0].state) {
|
||||
err = -EINVAL;
|
||||
dev_err(&pdev->dev, "error: adc_conditions not defined.\n");
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
data->adc_conditions = pdata->adc_conditions;
|
||||
|
||||
@ -138,10 +138,8 @@ static int adc_jack_probe(struct platform_device *pdev)
|
||||
data->num_conditions = i;
|
||||
|
||||
data->chan = iio_channel_get(&pdev->dev, pdata->consumer_channel);
|
||||
if (IS_ERR(data->chan)) {
|
||||
err = PTR_ERR(data->chan);
|
||||
goto out;
|
||||
}
|
||||
if (IS_ERR(data->chan))
|
||||
return PTR_ERR(data->chan);
|
||||
|
||||
data->handling_delay = msecs_to_jiffies(pdata->handling_delay_ms);
|
||||
|
||||
@ -149,15 +147,14 @@ static int adc_jack_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
err = extcon_dev_register(&data->edev);
|
||||
err = devm_extcon_dev_register(&pdev->dev, data->edev);
|
||||
if (err)
|
||||
goto out;
|
||||
return err;
|
||||
|
||||
data->irq = platform_get_irq(pdev, 0);
|
||||
if (!data->irq) {
|
||||
dev_err(&pdev->dev, "platform_get_irq failed\n");
|
||||
err = -ENODEV;
|
||||
goto err_irq;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = request_any_context_irq(data->irq, adc_jack_irq_thread,
|
||||
@ -165,15 +162,10 @@ static int adc_jack_probe(struct platform_device *pdev)
|
||||
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "error: irq %d\n", data->irq);
|
||||
goto err_irq;
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq:
|
||||
extcon_dev_unregister(&data->edev);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adc_jack_remove(struct platform_device *pdev)
|
||||
@ -182,7 +174,6 @@ static int adc_jack_remove(struct platform_device *pdev)
|
||||
|
||||
free_irq(data->irq, data);
|
||||
cancel_work_sync(&data->handler.work);
|
||||
extcon_dev_unregister(&data->edev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ struct arizona_extcon_info {
|
||||
|
||||
int hpdet_ip;
|
||||
|
||||
struct extcon_dev edev;
|
||||
struct extcon_dev *edev;
|
||||
};
|
||||
|
||||
static const struct arizona_micd_config micd_default_modes[] = {
|
||||
@ -546,7 +546,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
||||
}
|
||||
|
||||
/* If the cable was removed while measuring ignore the result */
|
||||
ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
|
||||
ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
|
||||
if (ret < 0) {
|
||||
dev_err(arizona->dev, "Failed to check cable state: %d\n",
|
||||
ret);
|
||||
@ -581,7 +581,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
||||
else
|
||||
report = ARIZONA_CABLE_HEADPHONE;
|
||||
|
||||
ret = extcon_set_cable_state_(&info->edev, report, true);
|
||||
ret = extcon_set_cable_state_(info->edev, report, true);
|
||||
if (ret != 0)
|
||||
dev_err(arizona->dev, "Failed to report HP/line: %d\n",
|
||||
ret);
|
||||
@ -664,7 +664,7 @@ err:
|
||||
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
|
||||
|
||||
/* Just report headphone */
|
||||
ret = extcon_update_state(&info->edev,
|
||||
ret = extcon_update_state(info->edev,
|
||||
1 << ARIZONA_CABLE_HEADPHONE,
|
||||
1 << ARIZONA_CABLE_HEADPHONE);
|
||||
if (ret != 0)
|
||||
@ -723,7 +723,7 @@ err:
|
||||
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
|
||||
|
||||
/* Just report headphone */
|
||||
ret = extcon_update_state(&info->edev,
|
||||
ret = extcon_update_state(info->edev,
|
||||
1 << ARIZONA_CABLE_HEADPHONE,
|
||||
1 << ARIZONA_CABLE_HEADPHONE);
|
||||
if (ret != 0)
|
||||
@ -764,7 +764,7 @@ static void arizona_micd_detect(struct work_struct *work)
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
/* If the cable was removed while measuring ignore the result */
|
||||
ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
|
||||
ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL);
|
||||
if (ret < 0) {
|
||||
dev_err(arizona->dev, "Failed to check cable state: %d\n",
|
||||
ret);
|
||||
@ -812,7 +812,7 @@ static void arizona_micd_detect(struct work_struct *work)
|
||||
if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
|
||||
arizona_identify_headphone(info);
|
||||
|
||||
ret = extcon_update_state(&info->edev,
|
||||
ret = extcon_update_state(info->edev,
|
||||
1 << ARIZONA_CABLE_MICROPHONE,
|
||||
1 << ARIZONA_CABLE_MICROPHONE);
|
||||
|
||||
@ -999,7 +999,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
|
||||
|
||||
if (info->last_jackdet == present) {
|
||||
dev_dbg(arizona->dev, "Detected jack\n");
|
||||
ret = extcon_set_cable_state_(&info->edev,
|
||||
ret = extcon_set_cable_state_(info->edev,
|
||||
ARIZONA_CABLE_MECHANICAL, true);
|
||||
|
||||
if (ret != 0)
|
||||
@ -1038,7 +1038,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
|
||||
info->micd_ranges[i].key, 0);
|
||||
input_sync(info->input);
|
||||
|
||||
ret = extcon_update_state(&info->edev, 0xffffffff, 0);
|
||||
ret = extcon_update_state(info->edev, 0xffffffff, 0);
|
||||
if (ret != 0)
|
||||
dev_err(arizona->dev, "Removal report failed: %d\n",
|
||||
ret);
|
||||
@ -1105,15 +1105,14 @@ static int arizona_extcon_probe(struct platform_device *pdev)
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
dev_err(&pdev->dev, "Failed to allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info->micvdd = devm_regulator_get(arizona->dev, "MICVDD");
|
||||
if (IS_ERR(info->micvdd)) {
|
||||
ret = PTR_ERR(info->micvdd);
|
||||
dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_init(&info->lock);
|
||||
@ -1151,15 +1150,19 @@ static int arizona_extcon_probe(struct platform_device *pdev)
|
||||
break;
|
||||
}
|
||||
|
||||
info->edev.name = "Headset Jack";
|
||||
info->edev.dev.parent = arizona->dev;
|
||||
info->edev.supported_cable = arizona_cable;
|
||||
info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable);
|
||||
if (IS_ERR(info->edev)) {
|
||||
dev_err(&pdev->dev, "failed to allocate extcon device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
info->edev->name = "Headset Jack";
|
||||
info->edev->dev.parent = arizona->dev;
|
||||
|
||||
ret = extcon_dev_register(&info->edev);
|
||||
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
|
||||
if (ret < 0) {
|
||||
dev_err(arizona->dev, "extcon_dev_register() failed: %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
info->input = devm_input_allocate_device(&pdev->dev);
|
||||
@ -1410,8 +1413,6 @@ err_rise:
|
||||
err_input:
|
||||
err_register:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
extcon_dev_unregister(&info->edev);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1445,7 +1446,6 @@ static int arizona_extcon_remove(struct platform_device *pdev)
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
|
||||
ARIZONA_JD1_ENA, 0);
|
||||
arizona_clk32k_disable(arizona);
|
||||
extcon_dev_unregister(&info->edev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -565,6 +565,100 @@ static void dummy_sysfs_dev_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* extcon_dev_allocate() - Allocate the memory of extcon device.
|
||||
* @supported_cable: Array of supported cable names ending with NULL.
|
||||
* If supported_cable is NULL, cable name related APIs
|
||||
* are disabled.
|
||||
*
|
||||
* This function allocates the memory for extcon device without allocating
|
||||
* memory in each extcon provider driver and initialize default setting for
|
||||
* extcon device.
|
||||
*
|
||||
* Return the pointer of extcon device if success or ERR_PTR(err) if fail
|
||||
*/
|
||||
struct extcon_dev *extcon_dev_allocate(const char **supported_cable)
|
||||
{
|
||||
struct extcon_dev *edev;
|
||||
|
||||
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
|
||||
if (!edev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
edev->max_supported = 0;
|
||||
edev->supported_cable = supported_cable;
|
||||
|
||||
return edev;
|
||||
}
|
||||
|
||||
/*
|
||||
* extcon_dev_free() - Free the memory of extcon device.
|
||||
* @edev: the extcon device to free
|
||||
*/
|
||||
void extcon_dev_free(struct extcon_dev *edev)
|
||||
{
|
||||
kfree(edev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(extcon_dev_free);
|
||||
|
||||
static int devm_extcon_dev_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct extcon_dev **r = res;
|
||||
|
||||
if (WARN_ON(!r || !*r))
|
||||
return 0;
|
||||
|
||||
return *r == data;
|
||||
}
|
||||
|
||||
static void devm_extcon_dev_release(struct device *dev, void *res)
|
||||
{
|
||||
extcon_dev_free(*(struct extcon_dev **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_extcon_dev_allocate - Allocate managed extcon device
|
||||
* @dev: device owning the extcon device being created
|
||||
* @supported_cable: Array of supported cable names ending with NULL.
|
||||
* If supported_cable is NULL, cable name related APIs
|
||||
* are disabled.
|
||||
*
|
||||
* This function manages automatically the memory of extcon device using device
|
||||
* resource management and simplify the control of freeing the memory of extcon
|
||||
* device.
|
||||
*
|
||||
* Returns the pointer memory of allocated extcon_dev if success
|
||||
* or ERR_PTR(err) if fail
|
||||
*/
|
||||
struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
|
||||
const char **supported_cable)
|
||||
{
|
||||
struct extcon_dev **ptr, *edev;
|
||||
|
||||
ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
edev = extcon_dev_allocate(supported_cable);
|
||||
if (IS_ERR(edev)) {
|
||||
devres_free(ptr);
|
||||
return edev;
|
||||
}
|
||||
|
||||
*ptr = edev;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return edev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate);
|
||||
|
||||
void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev)
|
||||
{
|
||||
WARN_ON(devres_release(dev, devm_extcon_dev_release,
|
||||
devm_extcon_dev_match, edev));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
|
||||
|
||||
/**
|
||||
* extcon_dev_register() - Register a new extcon device
|
||||
* @edev : the new extcon device (should be allocated before calling)
|
||||
@ -819,6 +913,63 @@ void extcon_dev_unregister(struct extcon_dev *edev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(extcon_dev_unregister);
|
||||
|
||||
static void devm_extcon_dev_unreg(struct device *dev, void *res)
|
||||
{
|
||||
extcon_dev_unregister(*(struct extcon_dev **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_extcon_dev_register() - Resource-managed extcon_dev_register()
|
||||
* @dev: device to allocate extcon device
|
||||
* @edev: the new extcon device to register
|
||||
*
|
||||
* Managed extcon_dev_register() function. If extcon device is attached with
|
||||
* this function, that extcon device is automatically unregistered on driver
|
||||
* detach. Internally this function calls extcon_dev_register() function.
|
||||
* To get more information, refer that function.
|
||||
*
|
||||
* If extcon device is registered with this function and the device needs to be
|
||||
* unregistered separately, devm_extcon_dev_unregister() should be used.
|
||||
*
|
||||
* Returns 0 if success or negaive error number if failure.
|
||||
*/
|
||||
int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev)
|
||||
{
|
||||
struct extcon_dev **ptr;
|
||||
int ret;
|
||||
|
||||
ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = extcon_dev_register(edev);
|
||||
if (ret) {
|
||||
devres_free(ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*ptr = edev;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_extcon_dev_register);
|
||||
|
||||
/**
|
||||
* devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister()
|
||||
* @dev: device the extcon belongs to
|
||||
* @edev: the extcon device to unregister
|
||||
*
|
||||
* Unregister extcon device that is registered with devm_extcon_dev_register()
|
||||
* function.
|
||||
*/
|
||||
void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev)
|
||||
{
|
||||
WARN_ON(devres_release(dev, devm_extcon_dev_unreg,
|
||||
devm_extcon_dev_match, edev));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/*
|
||||
* extcon_get_edev_by_phandle - Get the extcon device from devicetree
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <linux/extcon/extcon-gpio.h>
|
||||
|
||||
struct gpio_extcon_data {
|
||||
struct extcon_dev edev;
|
||||
struct extcon_dev *edev;
|
||||
unsigned gpio;
|
||||
bool gpio_active_low;
|
||||
const char *state_on;
|
||||
@ -53,7 +53,7 @@ static void gpio_extcon_work(struct work_struct *work)
|
||||
state = gpio_get_value(data->gpio);
|
||||
if (data->gpio_active_low)
|
||||
state = !state;
|
||||
extcon_set_state(&data->edev, state);
|
||||
extcon_set_state(data->edev, state);
|
||||
}
|
||||
|
||||
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
|
||||
@ -67,9 +67,10 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
|
||||
|
||||
static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf)
|
||||
{
|
||||
struct gpio_extcon_data *extcon_data =
|
||||
container_of(edev, struct gpio_extcon_data, edev);
|
||||
struct device *dev = edev->dev.parent;
|
||||
struct gpio_extcon_data *extcon_data = dev_get_drvdata(dev);
|
||||
const char *state;
|
||||
|
||||
if (extcon_get_state(edev))
|
||||
state = extcon_data->state_on;
|
||||
else
|
||||
@ -98,15 +99,21 @@ static int gpio_extcon_probe(struct platform_device *pdev)
|
||||
if (!extcon_data)
|
||||
return -ENOMEM;
|
||||
|
||||
extcon_data->edev.name = pdata->name;
|
||||
extcon_data->edev.dev.parent = &pdev->dev;
|
||||
extcon_data->edev = devm_extcon_dev_allocate(&pdev->dev, NULL);
|
||||
if (IS_ERR(extcon_data->edev)) {
|
||||
dev_err(&pdev->dev, "failed to allocate extcon device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
extcon_data->edev->name = pdata->name;
|
||||
extcon_data->edev->dev.parent = &pdev->dev;
|
||||
|
||||
extcon_data->gpio = pdata->gpio;
|
||||
extcon_data->gpio_active_low = pdata->gpio_active_low;
|
||||
extcon_data->state_on = pdata->state_on;
|
||||
extcon_data->state_off = pdata->state_off;
|
||||
extcon_data->check_on_resume = pdata->check_on_resume;
|
||||
if (pdata->state_on && pdata->state_off)
|
||||
extcon_data->edev.print_state = extcon_gpio_print_state;
|
||||
extcon_data->edev->print_state = extcon_gpio_print_state;
|
||||
|
||||
ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
|
||||
pdev->name);
|
||||
@ -121,34 +128,27 @@ static int gpio_extcon_probe(struct platform_device *pdev)
|
||||
msecs_to_jiffies(pdata->debounce);
|
||||
}
|
||||
|
||||
ret = extcon_dev_register(&extcon_data->edev);
|
||||
ret = devm_extcon_dev_register(&pdev->dev, extcon_data->edev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
|
||||
|
||||
extcon_data->irq = gpio_to_irq(extcon_data->gpio);
|
||||
if (extcon_data->irq < 0) {
|
||||
ret = extcon_data->irq;
|
||||
goto err;
|
||||
}
|
||||
if (extcon_data->irq < 0)
|
||||
return extcon_data->irq;
|
||||
|
||||
ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler,
|
||||
pdata->irq_flags, pdev->name,
|
||||
extcon_data);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, extcon_data);
|
||||
/* Perform initial detection */
|
||||
gpio_extcon_work(&extcon_data->work.work);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
extcon_dev_unregister(&extcon_data->edev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gpio_extcon_remove(struct platform_device *pdev)
|
||||
@ -157,7 +157,6 @@ static int gpio_extcon_remove(struct platform_device *pdev)
|
||||
|
||||
cancel_delayed_work_sync(&extcon_data->work);
|
||||
free_irq(extcon_data->irq, extcon_data);
|
||||
extcon_dev_unregister(&extcon_data->edev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* extcon-max14577.c - MAX14577 extcon driver to support MAX14577 MUIC
|
||||
* extcon-max14577.c - MAX14577/77836 extcon driver to support MUIC
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electrnoics
|
||||
* Copyright (C) 2013,2014 Samsung Electrnoics
|
||||
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
*
|
||||
* 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
|
||||
@ -24,7 +25,6 @@
|
||||
#include <linux/mfd/max14577-private.h>
|
||||
#include <linux/extcon.h>
|
||||
|
||||
#define DEV_NAME "max14577-muic"
|
||||
#define DELAY_MS_DEFAULT 17000 /* unit: millisecond */
|
||||
|
||||
enum max14577_muic_adc_debounce_time {
|
||||
@ -40,6 +40,42 @@ enum max14577_muic_status {
|
||||
MAX14577_MUIC_STATUS_END,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct max14577_muic_irq
|
||||
* @irq: the index of irq list of MUIC device.
|
||||
* @name: the name of irq.
|
||||
* @virq: the virtual irq to use irq domain
|
||||
*/
|
||||
struct max14577_muic_irq {
|
||||
unsigned int irq;
|
||||
const char *name;
|
||||
unsigned int virq;
|
||||
};
|
||||
|
||||
static struct max14577_muic_irq max14577_muic_irqs[] = {
|
||||
{ MAX14577_IRQ_INT1_ADC, "muic-ADC" },
|
||||
{ MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
|
||||
{ MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
|
||||
{ MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
|
||||
{ MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
|
||||
{ MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
|
||||
{ MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
|
||||
{ MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
|
||||
};
|
||||
|
||||
static struct max14577_muic_irq max77836_muic_irqs[] = {
|
||||
{ MAX14577_IRQ_INT1_ADC, "muic-ADC" },
|
||||
{ MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
|
||||
{ MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
|
||||
{ MAX77836_IRQ_INT1_ADC1K, "muic-ADC1K" },
|
||||
{ MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
|
||||
{ MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
|
||||
{ MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
|
||||
{ MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
|
||||
{ MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
|
||||
{ MAX77836_IRQ_INT2_VIDRM, "muic-VIDRM" },
|
||||
};
|
||||
|
||||
struct max14577_muic_info {
|
||||
struct device *dev;
|
||||
struct max14577 *max14577;
|
||||
@ -48,6 +84,8 @@ struct max14577_muic_info {
|
||||
int prev_chg_type;
|
||||
u8 status[MAX14577_MUIC_STATUS_END];
|
||||
|
||||
struct max14577_muic_irq *muic_irqs;
|
||||
unsigned int muic_irqs_num;
|
||||
bool irq_adc;
|
||||
bool irq_chg;
|
||||
struct work_struct irq_work;
|
||||
@ -74,29 +112,6 @@ enum max14577_muic_cable_group {
|
||||
MAX14577_CABLE_GROUP_CHG,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct max14577_muic_irq
|
||||
* @irq: the index of irq list of MUIC device.
|
||||
* @name: the name of irq.
|
||||
* @virq: the virtual irq to use irq domain
|
||||
*/
|
||||
struct max14577_muic_irq {
|
||||
unsigned int irq;
|
||||
const char *name;
|
||||
unsigned int virq;
|
||||
};
|
||||
|
||||
static struct max14577_muic_irq muic_irqs[] = {
|
||||
{ MAX14577_IRQ_INT1_ADC, "muic-ADC" },
|
||||
{ MAX14577_IRQ_INT1_ADCLOW, "muic-ADCLOW" },
|
||||
{ MAX14577_IRQ_INT1_ADCERR, "muic-ADCError" },
|
||||
{ MAX14577_IRQ_INT2_CHGTYP, "muic-CHGTYP" },
|
||||
{ MAX14577_IRQ_INT2_CHGDETRUN, "muic-CHGDETRUN" },
|
||||
{ MAX14577_IRQ_INT2_DCDTMR, "muic-DCDTMR" },
|
||||
{ MAX14577_IRQ_INT2_DBCHG, "muic-DBCHG" },
|
||||
{ MAX14577_IRQ_INT2_VBVOLT, "muic-VBVOLT" },
|
||||
};
|
||||
|
||||
/* Define supported accessory type */
|
||||
enum max14577_muic_acc_type {
|
||||
MAX14577_MUIC_ADC_GROUND = 0x0,
|
||||
@ -528,21 +543,12 @@ static void max14577_muic_irq_work(struct work_struct *work)
|
||||
return;
|
||||
}
|
||||
|
||||
static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
|
||||
/*
|
||||
* Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
|
||||
* Returns 0 if irq_type does not match registered IRQ for this device type.
|
||||
*/
|
||||
static int max14577_parse_irq(struct max14577_muic_info *info, int irq_type)
|
||||
{
|
||||
struct max14577_muic_info *info = data;
|
||||
int i, irq_type = -1;
|
||||
|
||||
/*
|
||||
* We may be called multiple times for different nested IRQ-s.
|
||||
* Including changes in INT1_ADC and INT2_CGHTYP at once.
|
||||
* However we only need to know whether it was ADC, charger
|
||||
* or both interrupts so decode IRQ and turn on proper flags.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
|
||||
if (irq == muic_irqs[i].virq)
|
||||
irq_type = muic_irqs[i].irq;
|
||||
|
||||
switch (irq_type) {
|
||||
case MAX14577_IRQ_INT1_ADC:
|
||||
case MAX14577_IRQ_INT1_ADCLOW:
|
||||
@ -550,7 +556,7 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
|
||||
/* Handle all of accessory except for
|
||||
type of charger accessory */
|
||||
info->irq_adc = true;
|
||||
break;
|
||||
return 1;
|
||||
case MAX14577_IRQ_INT2_CHGTYP:
|
||||
case MAX14577_IRQ_INT2_CHGDETRUN:
|
||||
case MAX14577_IRQ_INT2_DCDTMR:
|
||||
@ -558,8 +564,62 @@ static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
|
||||
case MAX14577_IRQ_INT2_VBVOLT:
|
||||
/* Handle charger accessory */
|
||||
info->irq_chg = true;
|
||||
break;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets irq_adc or irq_chg in max14577_muic_info and returns 1.
|
||||
* Returns 0 if irq_type does not match registered IRQ for this device type.
|
||||
*/
|
||||
static int max77836_parse_irq(struct max14577_muic_info *info, int irq_type)
|
||||
{
|
||||
/* First check common max14577 interrupts */
|
||||
if (max14577_parse_irq(info, irq_type))
|
||||
return 1;
|
||||
|
||||
switch (irq_type) {
|
||||
case MAX77836_IRQ_INT1_ADC1K:
|
||||
info->irq_adc = true;
|
||||
return 1;
|
||||
case MAX77836_IRQ_INT2_VIDRM:
|
||||
/* Handle charger accessory */
|
||||
info->irq_chg = true;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t max14577_muic_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct max14577_muic_info *info = data;
|
||||
int i, irq_type = -1;
|
||||
bool irq_parsed;
|
||||
|
||||
/*
|
||||
* We may be called multiple times for different nested IRQ-s.
|
||||
* Including changes in INT1_ADC and INT2_CGHTYP at once.
|
||||
* However we only need to know whether it was ADC, charger
|
||||
* or both interrupts so decode IRQ and turn on proper flags.
|
||||
*/
|
||||
for (i = 0; i < info->muic_irqs_num; i++)
|
||||
if (irq == info->muic_irqs[i].virq)
|
||||
irq_type = info->muic_irqs[i].irq;
|
||||
|
||||
switch (info->max14577->dev_type) {
|
||||
case MAXIM_DEVICE_TYPE_MAX77836:
|
||||
irq_parsed = max77836_parse_irq(info, irq_type);
|
||||
break;
|
||||
case MAXIM_DEVICE_TYPE_MAX14577:
|
||||
default:
|
||||
irq_parsed = max14577_parse_irq(info, irq_type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!irq_parsed) {
|
||||
dev_err(info->dev, "muic interrupt: irq %d occurred, skipped\n",
|
||||
irq_type);
|
||||
return IRQ_HANDLED;
|
||||
@ -644,13 +704,24 @@ static int max14577_muic_probe(struct platform_device *pdev)
|
||||
|
||||
INIT_WORK(&info->irq_work, max14577_muic_irq_work);
|
||||
|
||||
switch (max14577->dev_type) {
|
||||
case MAXIM_DEVICE_TYPE_MAX77836:
|
||||
info->muic_irqs = max77836_muic_irqs;
|
||||
info->muic_irqs_num = ARRAY_SIZE(max77836_muic_irqs);
|
||||
break;
|
||||
case MAXIM_DEVICE_TYPE_MAX14577:
|
||||
default:
|
||||
info->muic_irqs = max14577_muic_irqs;
|
||||
info->muic_irqs_num = ARRAY_SIZE(max14577_muic_irqs);
|
||||
}
|
||||
|
||||
/* Support irq domain for max14577 MUIC device */
|
||||
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
|
||||
struct max14577_muic_irq *muic_irq = &muic_irqs[i];
|
||||
for (i = 0; i < info->muic_irqs_num; i++) {
|
||||
struct max14577_muic_irq *muic_irq = &info->muic_irqs[i];
|
||||
unsigned int virq = 0;
|
||||
|
||||
virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq);
|
||||
if (!virq)
|
||||
if (virq <= 0)
|
||||
return -EINVAL;
|
||||
muic_irq->virq = virq;
|
||||
|
||||
@ -668,14 +739,16 @@ static int max14577_muic_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Initialize extcon device */
|
||||
info->edev = devm_kzalloc(&pdev->dev, sizeof(*info->edev), GFP_KERNEL);
|
||||
if (!info->edev) {
|
||||
info->edev = devm_extcon_dev_allocate(&pdev->dev,
|
||||
max14577_extcon_cable);
|
||||
if (IS_ERR(info->edev)) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
info->edev->name = DEV_NAME;
|
||||
info->edev->supported_cable = max14577_extcon_cable;
|
||||
ret = extcon_dev_register(info->edev);
|
||||
|
||||
info->edev->name = dev_name(&pdev->dev);
|
||||
|
||||
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register extcon device\n");
|
||||
return ret;
|
||||
@ -694,7 +767,7 @@ static int max14577_muic_probe(struct platform_device *pdev)
|
||||
MAX14577_REG_DEVICEID, &id);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to read revision number\n");
|
||||
goto err_extcon;
|
||||
return ret;
|
||||
}
|
||||
dev_info(info->dev, "device ID : 0x%x\n", id);
|
||||
|
||||
@ -710,19 +783,10 @@ static int max14577_muic_probe(struct platform_device *pdev)
|
||||
* driver should notify cable state to upper layer.
|
||||
*/
|
||||
INIT_DELAYED_WORK(&info->wq_detcable, max14577_muic_detect_cable_wq);
|
||||
ret = queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
|
||||
queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
|
||||
delay_jiffies);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to schedule delayed work for cable detect\n");
|
||||
goto err_extcon;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_extcon:
|
||||
extcon_dev_unregister(info->edev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max14577_muic_remove(struct platform_device *pdev)
|
||||
@ -730,23 +794,30 @@ static int max14577_muic_remove(struct platform_device *pdev)
|
||||
struct max14577_muic_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
cancel_work_sync(&info->irq_work);
|
||||
extcon_dev_unregister(info->edev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id max14577_muic_id[] = {
|
||||
{ "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, },
|
||||
{ "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max14577_muic_id);
|
||||
|
||||
static struct platform_driver max14577_muic_driver = {
|
||||
.driver = {
|
||||
.name = DEV_NAME,
|
||||
.name = "max14577-muic",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = max14577_muic_probe,
|
||||
.remove = max14577_muic_remove,
|
||||
.id_table = max14577_muic_id,
|
||||
};
|
||||
|
||||
module_platform_driver(max14577_muic_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 14577 Extcon driver");
|
||||
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
|
||||
MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver");
|
||||
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:extcon-max14577");
|
||||
|
@ -1175,25 +1175,24 @@ static int max77693_muic_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Initialize extcon device */
|
||||
info->edev = devm_kzalloc(&pdev->dev, sizeof(struct extcon_dev),
|
||||
GFP_KERNEL);
|
||||
if (!info->edev) {
|
||||
info->edev = devm_extcon_dev_allocate(&pdev->dev,
|
||||
max77693_extcon_cable);
|
||||
if (IS_ERR(info->edev)) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_irq;
|
||||
}
|
||||
info->edev->name = DEV_NAME;
|
||||
info->edev->dev.parent = &pdev->dev;
|
||||
info->edev->supported_cable = max77693_extcon_cable;
|
||||
ret = extcon_dev_register(info->edev);
|
||||
|
||||
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register extcon device\n");
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize MUIC register by using platform data or default data */
|
||||
if (pdata->muic_data) {
|
||||
if (pdata && pdata->muic_data) {
|
||||
init_data = pdata->muic_data->init_data;
|
||||
num_init_data = pdata->muic_data->num_init_data;
|
||||
} else {
|
||||
@ -1226,7 +1225,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
|
||||
= init_data[i].data;
|
||||
}
|
||||
|
||||
if (pdata->muic_data) {
|
||||
if (pdata && pdata->muic_data) {
|
||||
struct max77693_muic_platform_data *muic_pdata
|
||||
= pdata->muic_data;
|
||||
|
||||
@ -1267,7 +1266,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
|
||||
MAX77693_MUIC_REG_ID, &id);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to read revision number\n");
|
||||
goto err_extcon;
|
||||
goto err_irq;
|
||||
}
|
||||
dev_info(info->dev, "device ID : 0x%x\n", id);
|
||||
|
||||
@ -1283,12 +1282,11 @@ static int max77693_muic_probe(struct platform_device *pdev)
|
||||
* driver should notify cable state to upper layer.
|
||||
*/
|
||||
INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq);
|
||||
schedule_delayed_work(&info->wq_detcable, delay_jiffies);
|
||||
queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
|
||||
delay_jiffies);
|
||||
|
||||
return ret;
|
||||
|
||||
err_extcon:
|
||||
extcon_dev_unregister(info->edev);
|
||||
err_irq:
|
||||
while (--i >= 0)
|
||||
free_irq(muic_irqs[i].virq, info);
|
||||
@ -1304,7 +1302,6 @@ static int max77693_muic_remove(struct platform_device *pdev)
|
||||
free_irq(muic_irqs[i].virq, info);
|
||||
cancel_work_sync(&info->irq_work);
|
||||
input_unregister_device(info->dock);
|
||||
extcon_dev_unregister(info->edev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -699,23 +699,22 @@ static int max8997_muic_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* External connector */
|
||||
info->edev = devm_kzalloc(&pdev->dev, sizeof(struct extcon_dev),
|
||||
GFP_KERNEL);
|
||||
if (!info->edev) {
|
||||
info->edev = devm_extcon_dev_allocate(&pdev->dev, max8997_extcon_cable);
|
||||
if (IS_ERR(info->edev)) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_irq;
|
||||
}
|
||||
info->edev->name = DEV_NAME;
|
||||
info->edev->dev.parent = &pdev->dev;
|
||||
info->edev->supported_cable = max8997_extcon_cable;
|
||||
ret = extcon_dev_register(info->edev);
|
||||
|
||||
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register extcon device\n");
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
if (pdata->muic_pdata) {
|
||||
if (pdata && pdata->muic_pdata) {
|
||||
struct max8997_muic_platform_data *muic_pdata
|
||||
= pdata->muic_pdata;
|
||||
|
||||
@ -770,7 +769,8 @@ static int max8997_muic_probe(struct platform_device *pdev)
|
||||
* driver should notify cable state to upper layer.
|
||||
*/
|
||||
INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq);
|
||||
schedule_delayed_work(&info->wq_detcable, delay_jiffies);
|
||||
queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
|
||||
delay_jiffies);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -789,8 +789,6 @@ static int max8997_muic_remove(struct platform_device *pdev)
|
||||
free_irq(muic_irqs[i].virq, info);
|
||||
cancel_work_sync(&info->irq_work);
|
||||
|
||||
extcon_dev_unregister(info->edev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mfd/palmas.h>
|
||||
#include <linux/of.h>
|
||||
@ -56,7 +57,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
|
||||
if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) {
|
||||
if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
|
||||
palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
|
||||
extcon_set_cable_state(&palmas_usb->edev, "USB", true);
|
||||
extcon_set_cable_state(palmas_usb->edev, "USB", true);
|
||||
dev_info(palmas_usb->dev, "USB cable is attached\n");
|
||||
} else {
|
||||
dev_dbg(palmas_usb->dev,
|
||||
@ -65,7 +66,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
|
||||
} else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) {
|
||||
if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
|
||||
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
|
||||
extcon_set_cable_state(&palmas_usb->edev, "USB", false);
|
||||
extcon_set_cable_state(palmas_usb->edev, "USB", false);
|
||||
dev_info(palmas_usb->dev, "USB cable is detached\n");
|
||||
} else {
|
||||
dev_dbg(palmas_usb->dev,
|
||||
@ -92,7 +93,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
|
||||
PALMAS_USB_ID_INT_LATCH_CLR,
|
||||
PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
|
||||
palmas_usb->linkstat = PALMAS_USB_STATE_ID;
|
||||
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
|
||||
extcon_set_cable_state(palmas_usb->edev, "USB-HOST", true);
|
||||
dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
|
||||
} else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) &&
|
||||
(id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) {
|
||||
@ -100,17 +101,17 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
|
||||
PALMAS_USB_ID_INT_LATCH_CLR,
|
||||
PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
|
||||
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
|
||||
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
|
||||
extcon_set_cable_state(palmas_usb->edev, "USB-HOST", false);
|
||||
dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
|
||||
} else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
|
||||
(!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
|
||||
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
|
||||
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
|
||||
extcon_set_cable_state(palmas_usb->edev, "USB-HOST", false);
|
||||
dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
|
||||
} else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) &&
|
||||
(id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
|
||||
palmas_usb->linkstat = PALMAS_USB_STATE_ID;
|
||||
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
|
||||
extcon_set_cable_state(palmas_usb->edev, "USB-HOST", true);
|
||||
dev_info(palmas_usb->dev, " USB-HOST cable is attached\n");
|
||||
}
|
||||
|
||||
@ -186,13 +187,20 @@ static int palmas_usb_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, palmas_usb);
|
||||
|
||||
palmas_usb->edev.supported_cable = palmas_extcon_cable;
|
||||
palmas_usb->edev.dev.parent = palmas_usb->dev;
|
||||
palmas_usb->edev.mutually_exclusive = mutually_exclusive;
|
||||
palmas_usb->edev = devm_extcon_dev_allocate(&pdev->dev,
|
||||
palmas_extcon_cable);
|
||||
if (IS_ERR(palmas_usb->edev)) {
|
||||
dev_err(&pdev->dev, "failed to allocate extcon device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
palmas_usb->edev->name = kstrdup(node->name, GFP_KERNEL);
|
||||
palmas_usb->edev->dev.parent = palmas_usb->dev;
|
||||
palmas_usb->edev->mutually_exclusive = mutually_exclusive;
|
||||
|
||||
status = extcon_dev_register(&palmas_usb->edev);
|
||||
status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev);
|
||||
if (status) {
|
||||
dev_err(&pdev->dev, "failed to register extcon device\n");
|
||||
kfree(palmas_usb->edev->name);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -206,7 +214,8 @@ static int palmas_usb_probe(struct platform_device *pdev)
|
||||
if (status < 0) {
|
||||
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
|
||||
palmas_usb->id_irq, status);
|
||||
goto fail_extcon;
|
||||
kfree(palmas_usb->edev->name);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,25 +229,21 @@ static int palmas_usb_probe(struct platform_device *pdev)
|
||||
if (status < 0) {
|
||||
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
|
||||
palmas_usb->vbus_irq, status);
|
||||
goto fail_extcon;
|
||||
kfree(palmas_usb->edev->name);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
palmas_enable_irq(palmas_usb);
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
return 0;
|
||||
|
||||
fail_extcon:
|
||||
extcon_dev_unregister(&palmas_usb->edev);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int palmas_usb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
|
||||
|
||||
extcon_dev_unregister(&palmas_usb->edev);
|
||||
kfree(palmas_usb->edev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -331,15 +331,15 @@ config MFD_88PM860X
|
||||
battery-charger under the corresponding menus.
|
||||
|
||||
config MFD_MAX14577
|
||||
bool "Maxim Semiconductor MAX14577 MUIC + Charger Support"
|
||||
bool "Maxim Semiconductor MAX14577/77836 MUIC + Charger Support"
|
||||
depends on I2C=y
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
Say yes here to add support for Maxim Semiconductor MAX14577.
|
||||
This is a Micro-USB IC with Charger controls on chip.
|
||||
Say yes here to add support for Maxim Semiconductor MAX14577 and
|
||||
MAX77836 Micro-USB ICs with battery charger.
|
||||
This driver provides common support for accessing the device;
|
||||
additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* max14577.c - mfd core driver for the Maxim 14577
|
||||
* max14577.c - mfd core driver for the Maxim 14577/77836
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electrnoics
|
||||
* Copyright (C) 2014 Samsung Electrnoics
|
||||
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
*
|
||||
@ -21,6 +21,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/max14577.h>
|
||||
#include <linux/mfd/max14577-private.h>
|
||||
@ -37,7 +38,38 @@ static struct mfd_cell max14577_devs[] = {
|
||||
{ .name = "max14577-charger", },
|
||||
};
|
||||
|
||||
static bool max14577_volatile_reg(struct device *dev, unsigned int reg)
|
||||
static struct mfd_cell max77836_devs[] = {
|
||||
{
|
||||
.name = "max77836-muic",
|
||||
.of_compatible = "maxim,max77836-muic",
|
||||
},
|
||||
{
|
||||
.name = "max77836-regulator",
|
||||
.of_compatible = "maxim,max77836-regulator",
|
||||
},
|
||||
{
|
||||
.name = "max77836-charger",
|
||||
.of_compatible = "maxim,max77836-charger",
|
||||
},
|
||||
{
|
||||
.name = "max77836-battery",
|
||||
.of_compatible = "maxim,max77836-battery",
|
||||
},
|
||||
};
|
||||
|
||||
static struct of_device_id max14577_dt_match[] = {
|
||||
{
|
||||
.compatible = "maxim,max14577",
|
||||
.data = (void *)MAXIM_DEVICE_TYPE_MAX14577,
|
||||
},
|
||||
{
|
||||
.compatible = "maxim,max77836",
|
||||
.data = (void *)MAXIM_DEVICE_TYPE_MAX77836,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case MAX14577_REG_INT1 ... MAX14577_REG_STATUS3:
|
||||
@ -48,49 +80,221 @@ static bool max14577_volatile_reg(struct device *dev, unsigned int reg)
|
||||
return false;
|
||||
}
|
||||
|
||||
static const struct regmap_config max14577_regmap_config = {
|
||||
static bool max77836_muic_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
/* Any max14577 volatile registers are also max77836 volatile. */
|
||||
if (max14577_muic_volatile_reg(dev, reg))
|
||||
return true;
|
||||
|
||||
switch (reg) {
|
||||
case MAX77836_FG_REG_VCELL_MSB ... MAX77836_FG_REG_SOC_LSB:
|
||||
case MAX77836_FG_REG_CRATE_MSB ... MAX77836_FG_REG_CRATE_LSB:
|
||||
case MAX77836_FG_REG_STATUS_H ... MAX77836_FG_REG_STATUS_L:
|
||||
case MAX77836_PMIC_REG_INTSRC:
|
||||
case MAX77836_PMIC_REG_TOPSYS_INT:
|
||||
case MAX77836_PMIC_REG_TOPSYS_STAT:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const struct regmap_config max14577_muic_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_reg = max14577_volatile_reg,
|
||||
.volatile_reg = max14577_muic_volatile_reg,
|
||||
.max_register = MAX14577_REG_END,
|
||||
};
|
||||
|
||||
static const struct regmap_config max77836_pmic_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_reg = max77836_muic_volatile_reg,
|
||||
.max_register = MAX77836_PMIC_REG_END,
|
||||
};
|
||||
|
||||
static const struct regmap_irq max14577_irqs[] = {
|
||||
/* INT1 interrupts */
|
||||
{ .reg_offset = 0, .mask = INT1_ADC_MASK, },
|
||||
{ .reg_offset = 0, .mask = INT1_ADCLOW_MASK, },
|
||||
{ .reg_offset = 0, .mask = INT1_ADCERR_MASK, },
|
||||
{ .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
|
||||
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
|
||||
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
|
||||
/* INT2 interrupts */
|
||||
{ .reg_offset = 1, .mask = INT2_CHGTYP_MASK, },
|
||||
{ .reg_offset = 1, .mask = INT2_CHGDETRUN_MASK, },
|
||||
{ .reg_offset = 1, .mask = INT2_DCDTMR_MASK, },
|
||||
{ .reg_offset = 1, .mask = INT2_DBCHG_MASK, },
|
||||
{ .reg_offset = 1, .mask = INT2_VBVOLT_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
|
||||
/* INT3 interrupts */
|
||||
{ .reg_offset = 2, .mask = INT3_EOC_MASK, },
|
||||
{ .reg_offset = 2, .mask = INT3_CGMBC_MASK, },
|
||||
{ .reg_offset = 2, .mask = INT3_OVP_MASK, },
|
||||
{ .reg_offset = 2, .mask = INT3_MBCCHGERR_MASK, },
|
||||
{ .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
|
||||
{ .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
|
||||
{ .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
|
||||
{ .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip max14577_irq_chip = {
|
||||
.name = "max14577",
|
||||
.status_base = MAX14577_REG_INT1,
|
||||
.mask_base = MAX14577_REG_INTMASK1,
|
||||
.mask_invert = 1,
|
||||
.mask_invert = true,
|
||||
.num_regs = 3,
|
||||
.irqs = max14577_irqs,
|
||||
.num_irqs = ARRAY_SIZE(max14577_irqs),
|
||||
};
|
||||
|
||||
static const struct regmap_irq max77836_muic_irqs[] = {
|
||||
/* INT1 interrupts */
|
||||
{ .reg_offset = 0, .mask = MAX14577_INT1_ADC_MASK, },
|
||||
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCLOW_MASK, },
|
||||
{ .reg_offset = 0, .mask = MAX14577_INT1_ADCERR_MASK, },
|
||||
{ .reg_offset = 0, .mask = MAX77836_INT1_ADC1K_MASK, },
|
||||
/* INT2 interrupts */
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGTYP_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_CHGDETRUN_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_DCDTMR_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_DBCHG_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX14577_INT2_VBVOLT_MASK, },
|
||||
{ .reg_offset = 1, .mask = MAX77836_INT2_VIDRM_MASK, },
|
||||
/* INT3 interrupts */
|
||||
{ .reg_offset = 2, .mask = MAX14577_INT3_EOC_MASK, },
|
||||
{ .reg_offset = 2, .mask = MAX14577_INT3_CGMBC_MASK, },
|
||||
{ .reg_offset = 2, .mask = MAX14577_INT3_OVP_MASK, },
|
||||
{ .reg_offset = 2, .mask = MAX14577_INT3_MBCCHGERR_MASK, },
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip max77836_muic_irq_chip = {
|
||||
.name = "max77836-muic",
|
||||
.status_base = MAX14577_REG_INT1,
|
||||
.mask_base = MAX14577_REG_INTMASK1,
|
||||
.mask_invert = true,
|
||||
.num_regs = 3,
|
||||
.irqs = max77836_muic_irqs,
|
||||
.num_irqs = ARRAY_SIZE(max77836_muic_irqs),
|
||||
};
|
||||
|
||||
static const struct regmap_irq max77836_pmic_irqs[] = {
|
||||
{ .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T120C_MASK, },
|
||||
{ .reg_offset = 0, .mask = MAX77836_TOPSYS_INT_T140C_MASK, },
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip max77836_pmic_irq_chip = {
|
||||
.name = "max77836-pmic",
|
||||
.status_base = MAX77836_PMIC_REG_TOPSYS_INT,
|
||||
.mask_base = MAX77836_PMIC_REG_TOPSYS_INT_MASK,
|
||||
.mask_invert = false,
|
||||
.num_regs = 1,
|
||||
.irqs = max77836_pmic_irqs,
|
||||
.num_irqs = ARRAY_SIZE(max77836_pmic_irqs),
|
||||
};
|
||||
|
||||
static void max14577_print_dev_type(struct max14577 *max14577)
|
||||
{
|
||||
u8 reg_data, vendor_id, device_id;
|
||||
int ret;
|
||||
|
||||
ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
|
||||
®_data);
|
||||
if (ret) {
|
||||
dev_err(max14577->dev,
|
||||
"Failed to read DEVICEID register: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
vendor_id = ((reg_data & DEVID_VENDORID_MASK) >>
|
||||
DEVID_VENDORID_SHIFT);
|
||||
device_id = ((reg_data & DEVID_DEVICEID_MASK) >>
|
||||
DEVID_DEVICEID_SHIFT);
|
||||
|
||||
dev_info(max14577->dev, "Device type: %u (ID: 0x%x, vendor: 0x%x)\n",
|
||||
max14577->dev_type, device_id, vendor_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Max77836 specific initialization code for driver probe.
|
||||
* Adds new I2C dummy device, regmap and regmap IRQ chip.
|
||||
* Unmasks Interrupt Source register.
|
||||
*
|
||||
* On success returns 0.
|
||||
* On failure returns errno and reverts any changes done so far (e.g. remove
|
||||
* I2C dummy device), except masking the INT SRC register.
|
||||
*/
|
||||
static int max77836_init(struct max14577 *max14577)
|
||||
{
|
||||
int ret;
|
||||
u8 intsrc_mask;
|
||||
|
||||
max14577->i2c_pmic = i2c_new_dummy(max14577->i2c->adapter,
|
||||
I2C_ADDR_PMIC);
|
||||
if (!max14577->i2c_pmic) {
|
||||
dev_err(max14577->dev, "Failed to register PMIC I2C device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
i2c_set_clientdata(max14577->i2c_pmic, max14577);
|
||||
|
||||
max14577->regmap_pmic = devm_regmap_init_i2c(max14577->i2c_pmic,
|
||||
&max77836_pmic_regmap_config);
|
||||
if (IS_ERR(max14577->regmap_pmic)) {
|
||||
ret = PTR_ERR(max14577->regmap_pmic);
|
||||
dev_err(max14577->dev, "Failed to allocate PMIC register map: %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Un-mask MAX77836 Interrupt Source register */
|
||||
ret = max14577_read_reg(max14577->regmap_pmic,
|
||||
MAX77836_PMIC_REG_INTSRC_MASK, &intsrc_mask);
|
||||
if (ret < 0) {
|
||||
dev_err(max14577->dev, "Failed to read PMIC register\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
intsrc_mask &= ~(MAX77836_INTSRC_MASK_TOP_INT_MASK);
|
||||
intsrc_mask &= ~(MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK);
|
||||
ret = max14577_write_reg(max14577->regmap_pmic,
|
||||
MAX77836_PMIC_REG_INTSRC_MASK, intsrc_mask);
|
||||
if (ret < 0) {
|
||||
dev_err(max14577->dev, "Failed to write PMIC register\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = regmap_add_irq_chip(max14577->regmap_pmic, max14577->irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED,
|
||||
0, &max77836_pmic_irq_chip,
|
||||
&max14577->irq_data_pmic);
|
||||
if (ret != 0) {
|
||||
dev_err(max14577->dev, "Failed to request PMIC IRQ %d: %d\n",
|
||||
max14577->irq, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
i2c_unregister_device(max14577->i2c_pmic);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Max77836 specific de-initialization code for driver remove.
|
||||
*/
|
||||
static void max77836_remove(struct max14577 *max14577)
|
||||
{
|
||||
regmap_del_irq_chip(max14577->irq, max14577->irq_data_pmic);
|
||||
i2c_unregister_device(max14577->i2c_pmic);
|
||||
}
|
||||
|
||||
static int max14577_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct max14577 *max14577;
|
||||
struct max14577_platform_data *pdata = dev_get_platdata(&i2c->dev);
|
||||
struct device_node *np = i2c->dev.of_node;
|
||||
u8 reg_data;
|
||||
int ret = 0;
|
||||
const struct regmap_irq_chip *irq_chip;
|
||||
struct mfd_cell *mfd_devs;
|
||||
unsigned int mfd_devs_size;
|
||||
int irq_flags;
|
||||
|
||||
if (np) {
|
||||
pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
@ -113,7 +317,8 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
|
||||
max14577->i2c = i2c;
|
||||
max14577->irq = i2c->irq;
|
||||
|
||||
max14577->regmap = devm_regmap_init_i2c(i2c, &max14577_regmap_config);
|
||||
max14577->regmap = devm_regmap_init_i2c(i2c,
|
||||
&max14577_muic_regmap_config);
|
||||
if (IS_ERR(max14577->regmap)) {
|
||||
ret = PTR_ERR(max14577->regmap);
|
||||
dev_err(max14577->dev, "Failed to allocate register map: %d\n",
|
||||
@ -121,23 +326,36 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max14577_read_reg(max14577->regmap, MAX14577_REG_DEVICEID,
|
||||
®_data);
|
||||
if (ret) {
|
||||
dev_err(max14577->dev, "Device not found on this channel: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
if (np) {
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
of_id = of_match_device(max14577_dt_match, &i2c->dev);
|
||||
if (of_id)
|
||||
max14577->dev_type = (unsigned int)of_id->data;
|
||||
} else {
|
||||
max14577->dev_type = id->driver_data;
|
||||
}
|
||||
|
||||
max14577_print_dev_type(max14577);
|
||||
|
||||
switch (max14577->dev_type) {
|
||||
case MAXIM_DEVICE_TYPE_MAX77836:
|
||||
irq_chip = &max77836_muic_irq_chip;
|
||||
mfd_devs = max77836_devs;
|
||||
mfd_devs_size = ARRAY_SIZE(max77836_devs);
|
||||
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_SHARED;
|
||||
break;
|
||||
case MAXIM_DEVICE_TYPE_MAX14577:
|
||||
default:
|
||||
irq_chip = &max14577_irq_chip;
|
||||
mfd_devs = max14577_devs;
|
||||
mfd_devs_size = ARRAY_SIZE(max14577_devs);
|
||||
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
|
||||
break;
|
||||
}
|
||||
max14577->vendor_id = ((reg_data & DEVID_VENDORID_MASK) >>
|
||||
DEVID_VENDORID_SHIFT);
|
||||
max14577->device_id = ((reg_data & DEVID_DEVICEID_MASK) >>
|
||||
DEVID_DEVICEID_SHIFT);
|
||||
dev_info(max14577->dev, "Device ID: 0x%x, vendor: 0x%x\n",
|
||||
max14577->device_id, max14577->vendor_id);
|
||||
|
||||
ret = regmap_add_irq_chip(max14577->regmap, max14577->irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
|
||||
&max14577_irq_chip,
|
||||
irq_flags, 0, irq_chip,
|
||||
&max14577->irq_data);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
|
||||
@ -145,8 +363,15 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(max14577->dev, -1, max14577_devs,
|
||||
ARRAY_SIZE(max14577_devs), NULL, 0,
|
||||
/* Max77836 specific initialization code (additional regmap) */
|
||||
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) {
|
||||
ret = max77836_init(max14577);
|
||||
if (ret < 0)
|
||||
goto err_max77836;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(max14577->dev, -1, mfd_devs,
|
||||
mfd_devs_size, NULL, 0,
|
||||
regmap_irq_get_domain(max14577->irq_data));
|
||||
if (ret < 0)
|
||||
goto err_mfd;
|
||||
@ -156,6 +381,9 @@ static int max14577_i2c_probe(struct i2c_client *i2c,
|
||||
return 0;
|
||||
|
||||
err_mfd:
|
||||
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
|
||||
max77836_remove(max14577);
|
||||
err_max77836:
|
||||
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
|
||||
|
||||
return ret;
|
||||
@ -167,12 +395,15 @@ static int max14577_i2c_remove(struct i2c_client *i2c)
|
||||
|
||||
mfd_remove_devices(max14577->dev);
|
||||
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
|
||||
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
|
||||
max77836_remove(max14577);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max14577_i2c_id[] = {
|
||||
{ "max14577", 0 },
|
||||
{ "max14577", MAXIM_DEVICE_TYPE_MAX14577, },
|
||||
{ "max77836", MAXIM_DEVICE_TYPE_MAX77836, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
|
||||
@ -215,11 +446,6 @@ static int max14577_resume(struct device *dev)
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static struct of_device_id max14577_dt_match[] = {
|
||||
{ .compatible = "maxim,max14577", },
|
||||
{},
|
||||
};
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max14577_pm, max14577_suspend, max14577_resume);
|
||||
|
||||
static struct i2c_driver max14577_i2c_driver = {
|
||||
@ -236,6 +462,9 @@ static struct i2c_driver max14577_i2c_driver = {
|
||||
|
||||
static int __init max14577_i2c_init(void)
|
||||
{
|
||||
BUILD_BUG_ON(ARRAY_SIZE(max14577_i2c_id) != MAXIM_DEVICE_TYPE_NUM);
|
||||
BUILD_BUG_ON(ARRAY_SIZE(max14577_dt_match) != MAXIM_DEVICE_TYPE_NUM);
|
||||
|
||||
return i2c_add_driver(&max14577_i2c_driver);
|
||||
}
|
||||
subsys_initcall(max14577_i2c_init);
|
||||
@ -247,5 +476,5 @@ static void __exit max14577_i2c_exit(void)
|
||||
module_exit(max14577_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
|
||||
MODULE_DESCRIPTION("MAXIM 14577 multi-function core driver");
|
||||
MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -266,11 +266,12 @@ config REGULATOR_LP8788
|
||||
This driver supports LP8788 voltage regulator chip.
|
||||
|
||||
config REGULATOR_MAX14577
|
||||
tristate "Maxim 14577 regulator"
|
||||
tristate "Maxim 14577/77836 regulator"
|
||||
depends on MFD_MAX14577
|
||||
help
|
||||
This driver controls a Maxim 14577 regulator via I2C bus.
|
||||
The regulators include safeout LDO and current regulator 'CHARGER'.
|
||||
This driver controls a Maxim MAX14577/77836 regulator via I2C bus.
|
||||
The MAX14577 regulators include safeout LDO and charger current
|
||||
regulator. The MAX77836 has two additional LDOs.
|
||||
|
||||
config REGULATOR_MAX1586
|
||||
tristate "Maxim 1586/1587 voltage regulator"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* max14577.c - Regulator driver for the Maxim 14577
|
||||
* max14577.c - Regulator driver for the Maxim 14577/77836
|
||||
*
|
||||
* Copyright (C) 2013,2014 Samsung Electronics
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
@ -22,6 +22,42 @@
|
||||
#include <linux/mfd/max14577-private.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
/*
|
||||
* Valid limits of current for max14577 and max77836 chargers.
|
||||
* They must correspond to MBCICHWRCL and MBCICHWRCH fields in CHGCTRL4
|
||||
* register for given chipset.
|
||||
*/
|
||||
struct maxim_charger_current {
|
||||
/* Minimal current, set in CHGCTRL4/MBCICHWRCL, uA */
|
||||
unsigned int min;
|
||||
/*
|
||||
* Minimal current when high setting is active,
|
||||
* set in CHGCTRL4/MBCICHWRCH, uA
|
||||
*/
|
||||
unsigned int high_start;
|
||||
/* Value of one step in high setting, uA */
|
||||
unsigned int high_step;
|
||||
/* Maximum current of high setting, uA */
|
||||
unsigned int max;
|
||||
};
|
||||
|
||||
/* Table of valid charger currents for different Maxim chipsets */
|
||||
static const struct maxim_charger_current maxim_charger_currents[] = {
|
||||
[MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 },
|
||||
[MAXIM_DEVICE_TYPE_MAX14577] = {
|
||||
.min = MAX14577_REGULATOR_CURRENT_LIMIT_MIN,
|
||||
.high_start = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START,
|
||||
.high_step = MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
|
||||
.max = MAX14577_REGULATOR_CURRENT_LIMIT_MAX,
|
||||
},
|
||||
[MAXIM_DEVICE_TYPE_MAX77836] = {
|
||||
.min = MAX77836_REGULATOR_CURRENT_LIMIT_MIN,
|
||||
.high_start = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START,
|
||||
.high_step = MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP,
|
||||
.max = MAX77836_REGULATOR_CURRENT_LIMIT_MAX,
|
||||
},
|
||||
};
|
||||
|
||||
static int max14577_reg_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
int rid = rdev_get_id(rdev);
|
||||
@ -47,6 +83,9 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
|
||||
{
|
||||
u8 reg_data;
|
||||
struct regmap *rmap = rdev->regmap;
|
||||
struct max14577 *max14577 = rdev_get_drvdata(rdev);
|
||||
const struct maxim_charger_current *limits =
|
||||
&maxim_charger_currents[max14577->dev_type];
|
||||
|
||||
if (rdev_get_id(rdev) != MAX14577_CHARGER)
|
||||
return -EINVAL;
|
||||
@ -54,12 +93,11 @@ static int max14577_reg_get_current_limit(struct regulator_dev *rdev)
|
||||
max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data);
|
||||
|
||||
if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0)
|
||||
return MAX14577_REGULATOR_CURRENT_LIMIT_MIN;
|
||||
return limits->min;
|
||||
|
||||
reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >>
|
||||
CHGCTRL4_MBCICHWRCH_SHIFT);
|
||||
return MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
|
||||
reg_data * MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP;
|
||||
return limits->high_start + reg_data * limits->high_step;
|
||||
}
|
||||
|
||||
static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
|
||||
@ -67,33 +105,39 @@ static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
|
||||
{
|
||||
int i, current_bits = 0xf;
|
||||
u8 reg_data;
|
||||
struct max14577 *max14577 = rdev_get_drvdata(rdev);
|
||||
const struct maxim_charger_current *limits =
|
||||
&maxim_charger_currents[max14577->dev_type];
|
||||
|
||||
if (rdev_get_id(rdev) != MAX14577_CHARGER)
|
||||
return -EINVAL;
|
||||
|
||||
if (min_uA > MAX14577_REGULATOR_CURRENT_LIMIT_MAX ||
|
||||
max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_MIN)
|
||||
if (min_uA > limits->max || max_uA < limits->min)
|
||||
return -EINVAL;
|
||||
|
||||
if (max_uA < MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START) {
|
||||
/* Less than 200 mA, so set 90mA (turn only Low Bit off) */
|
||||
if (max_uA < limits->high_start) {
|
||||
/*
|
||||
* Less than high_start,
|
||||
* so set the minimal current (turn only Low Bit off)
|
||||
*/
|
||||
u8 reg_data = 0x0 << CHGCTRL4_MBCICHWRCL_SHIFT;
|
||||
return max14577_update_reg(rdev->regmap,
|
||||
MAX14577_CHG_REG_CHG_CTRL4,
|
||||
CHGCTRL4_MBCICHWRCL_MASK, reg_data);
|
||||
}
|
||||
|
||||
/* max_uA is in range: <LIMIT_HIGH_START, inifinite>, so search for
|
||||
* valid current starting from LIMIT_MAX. */
|
||||
for (i = MAX14577_REGULATOR_CURRENT_LIMIT_MAX;
|
||||
i >= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START;
|
||||
i -= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP) {
|
||||
/*
|
||||
* max_uA is in range: <high_start, inifinite>, so search for
|
||||
* valid current starting from maximum current.
|
||||
*/
|
||||
for (i = limits->max; i >= limits->high_start; i -= limits->high_step) {
|
||||
if (i <= max_uA)
|
||||
break;
|
||||
current_bits--;
|
||||
}
|
||||
BUG_ON(current_bits < 0); /* Cannot happen */
|
||||
/* Turn Low Bit on (use range 200mA-950 mA) */
|
||||
|
||||
/* Turn Low Bit on (use range high_start-max)... */
|
||||
reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT;
|
||||
/* and set proper High Bits */
|
||||
reg_data |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT;
|
||||
@ -118,7 +162,7 @@ static struct regulator_ops max14577_charger_ops = {
|
||||
.set_current_limit = max14577_reg_set_current_limit,
|
||||
};
|
||||
|
||||
static const struct regulator_desc supported_regulators[] = {
|
||||
static const struct regulator_desc max14577_supported_regulators[] = {
|
||||
[MAX14577_SAFEOUT] = {
|
||||
.name = "SAFEOUT",
|
||||
.id = MAX14577_SAFEOUT,
|
||||
@ -141,16 +185,88 @@ static const struct regulator_desc supported_regulators[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct regulator_ops max77836_ldo_ops = {
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.map_voltage = regulator_map_voltage_linear,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
/* TODO: add .set_suspend_mode */
|
||||
};
|
||||
|
||||
static const struct regulator_desc max77836_supported_regulators[] = {
|
||||
[MAX14577_SAFEOUT] = {
|
||||
.name = "SAFEOUT",
|
||||
.id = MAX14577_SAFEOUT,
|
||||
.ops = &max14577_safeout_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.n_voltages = 1,
|
||||
.min_uV = MAX14577_REGULATOR_SAFEOUT_VOLTAGE,
|
||||
.enable_reg = MAX14577_REG_CONTROL2,
|
||||
.enable_mask = CTRL2_SFOUTORD_MASK,
|
||||
},
|
||||
[MAX14577_CHARGER] = {
|
||||
.name = "CHARGER",
|
||||
.id = MAX14577_CHARGER,
|
||||
.ops = &max14577_charger_ops,
|
||||
.type = REGULATOR_CURRENT,
|
||||
.owner = THIS_MODULE,
|
||||
.enable_reg = MAX14577_CHG_REG_CHG_CTRL2,
|
||||
.enable_mask = CHGCTRL2_MBCHOSTEN_MASK,
|
||||
},
|
||||
[MAX77836_LDO1] = {
|
||||
.name = "LDO1",
|
||||
.id = MAX77836_LDO1,
|
||||
.ops = &max77836_ldo_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
|
||||
.min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
|
||||
.uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
|
||||
.enable_reg = MAX77836_LDO_REG_CNFG1_LDO1,
|
||||
.enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK,
|
||||
.vsel_reg = MAX77836_LDO_REG_CNFG1_LDO1,
|
||||
.vsel_mask = MAX77836_CNFG1_LDO_TV_MASK,
|
||||
},
|
||||
[MAX77836_LDO2] = {
|
||||
.name = "LDO2",
|
||||
.id = MAX77836_LDO2,
|
||||
.ops = &max77836_ldo_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.n_voltages = MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM,
|
||||
.min_uV = MAX77836_REGULATOR_LDO_VOLTAGE_MIN,
|
||||
.uV_step = MAX77836_REGULATOR_LDO_VOLTAGE_STEP,
|
||||
.enable_reg = MAX77836_LDO_REG_CNFG1_LDO2,
|
||||
.enable_mask = MAX77836_CNFG1_LDO_PWRMD_MASK,
|
||||
.vsel_reg = MAX77836_LDO_REG_CNFG1_LDO2,
|
||||
.vsel_mask = MAX77836_CNFG1_LDO_TV_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_regulator_match max14577_regulator_matches[] = {
|
||||
{ .name = "SAFEOUT", },
|
||||
{ .name = "CHARGER", },
|
||||
};
|
||||
|
||||
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
|
||||
static struct of_regulator_match max77836_regulator_matches[] = {
|
||||
{ .name = "SAFEOUT", },
|
||||
{ .name = "CHARGER", },
|
||||
{ .name = "LDO1", },
|
||||
{ .name = "LDO2", },
|
||||
};
|
||||
|
||||
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
|
||||
enum maxim_device_type dev_type)
|
||||
{
|
||||
int ret;
|
||||
struct device_node *np;
|
||||
struct of_regulator_match *regulator_matches;
|
||||
unsigned int regulator_matches_size;
|
||||
|
||||
np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
|
||||
if (!np) {
|
||||
@ -158,8 +274,19 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
|
||||
MAX14577_REG_MAX);
|
||||
switch (dev_type) {
|
||||
case MAXIM_DEVICE_TYPE_MAX77836:
|
||||
regulator_matches = max77836_regulator_matches;
|
||||
regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches);
|
||||
break;
|
||||
case MAXIM_DEVICE_TYPE_MAX14577:
|
||||
default:
|
||||
regulator_matches = max14577_regulator_matches;
|
||||
regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches);
|
||||
}
|
||||
|
||||
ret = of_regulator_match(&pdev->dev, np, regulator_matches,
|
||||
regulator_matches_size);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
|
||||
else
|
||||
@ -170,31 +297,74 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline struct regulator_init_data *match_init_data(int index)
|
||||
static inline struct regulator_init_data *match_init_data(int index,
|
||||
enum maxim_device_type dev_type)
|
||||
{
|
||||
return max14577_regulator_matches[index].init_data;
|
||||
switch (dev_type) {
|
||||
case MAXIM_DEVICE_TYPE_MAX77836:
|
||||
return max77836_regulator_matches[index].init_data;
|
||||
|
||||
case MAXIM_DEVICE_TYPE_MAX14577:
|
||||
default:
|
||||
return max14577_regulator_matches[index].init_data;
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct device_node *match_of_node(int index)
|
||||
static inline struct device_node *match_of_node(int index,
|
||||
enum maxim_device_type dev_type)
|
||||
{
|
||||
return max14577_regulator_matches[index].of_node;
|
||||
switch (dev_type) {
|
||||
case MAXIM_DEVICE_TYPE_MAX77836:
|
||||
return max77836_regulator_matches[index].of_node;
|
||||
|
||||
case MAXIM_DEVICE_TYPE_MAX14577:
|
||||
default:
|
||||
return max14577_regulator_matches[index].of_node;
|
||||
}
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
|
||||
static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
|
||||
enum maxim_device_type dev_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline struct regulator_init_data *match_init_data(int index)
|
||||
static inline struct regulator_init_data *match_init_data(int index,
|
||||
enum maxim_device_type dev_type)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct device_node *match_of_node(int index)
|
||||
static inline struct device_node *match_of_node(int index,
|
||||
enum maxim_device_type dev_type)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/**
|
||||
* Registers for regulators of max77836 use different I2C slave addresses so
|
||||
* different regmaps must be used for them.
|
||||
*
|
||||
* Returns proper regmap for accessing regulator passed by id.
|
||||
*/
|
||||
static struct regmap *max14577_get_regmap(struct max14577 *max14577,
|
||||
int reg_id)
|
||||
{
|
||||
switch (max14577->dev_type) {
|
||||
case MAXIM_DEVICE_TYPE_MAX77836:
|
||||
switch (reg_id) {
|
||||
case MAX77836_SAFEOUT ... MAX77836_CHARGER:
|
||||
return max14577->regmap;
|
||||
default:
|
||||
/* MAX77836_LDO1 ... MAX77836_LDO2 */
|
||||
return max14577->regmap_pmic;
|
||||
}
|
||||
|
||||
case MAXIM_DEVICE_TYPE_MAX14577:
|
||||
default:
|
||||
return max14577->regmap;
|
||||
}
|
||||
}
|
||||
|
||||
static int max14577_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -202,15 +372,29 @@ static int max14577_regulator_probe(struct platform_device *pdev)
|
||||
struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev);
|
||||
int i, ret;
|
||||
struct regulator_config config = {};
|
||||
const struct regulator_desc *supported_regulators;
|
||||
unsigned int supported_regulators_size;
|
||||
enum maxim_device_type dev_type = max14577->dev_type;
|
||||
|
||||
ret = max14577_regulator_dt_parse_pdata(pdev);
|
||||
ret = max14577_regulator_dt_parse_pdata(pdev, dev_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.regmap = max14577->regmap;
|
||||
switch (dev_type) {
|
||||
case MAXIM_DEVICE_TYPE_MAX77836:
|
||||
supported_regulators = max77836_supported_regulators;
|
||||
supported_regulators_size = ARRAY_SIZE(max77836_supported_regulators);
|
||||
break;
|
||||
case MAXIM_DEVICE_TYPE_MAX14577:
|
||||
default:
|
||||
supported_regulators = max14577_supported_regulators;
|
||||
supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
|
||||
config.dev = &pdev->dev;
|
||||
config.driver_data = max14577;
|
||||
|
||||
for (i = 0; i < supported_regulators_size; i++) {
|
||||
struct regulator_dev *regulator;
|
||||
/*
|
||||
* Index of supported_regulators[] is also the id and must
|
||||
@ -220,17 +404,19 @@ static int max14577_regulator_probe(struct platform_device *pdev)
|
||||
config.init_data = pdata->regulators[i].initdata;
|
||||
config.of_node = pdata->regulators[i].of_node;
|
||||
} else {
|
||||
config.init_data = match_init_data(i);
|
||||
config.of_node = match_of_node(i);
|
||||
config.init_data = match_init_data(i, dev_type);
|
||||
config.of_node = match_of_node(i, dev_type);
|
||||
}
|
||||
config.regmap = max14577_get_regmap(max14577,
|
||||
supported_regulators[i].id);
|
||||
|
||||
regulator = devm_regulator_register(&pdev->dev,
|
||||
&supported_regulators[i], &config);
|
||||
if (IS_ERR(regulator)) {
|
||||
ret = PTR_ERR(regulator);
|
||||
dev_err(&pdev->dev,
|
||||
"Regulator init failed for ID %d with error: %d\n",
|
||||
i, ret);
|
||||
"Regulator init failed for %d/%s with error: %d\n",
|
||||
i, supported_regulators[i].name, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -238,20 +424,41 @@ static int max14577_regulator_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct platform_device_id max14577_regulator_id[] = {
|
||||
{ "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, },
|
||||
{ "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max14577_regulator_id);
|
||||
|
||||
static struct platform_driver max14577_regulator_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "max14577-regulator",
|
||||
},
|
||||
.probe = max14577_regulator_probe,
|
||||
.probe = max14577_regulator_probe,
|
||||
.id_table = max14577_regulator_id,
|
||||
};
|
||||
|
||||
static int __init max14577_regulator_init(void)
|
||||
{
|
||||
/* Check for valid values for charger */
|
||||
BUILD_BUG_ON(MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START +
|
||||
MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
|
||||
MAX14577_REGULATOR_CURRENT_LIMIT_MAX);
|
||||
BUILD_BUG_ON(ARRAY_SIZE(supported_regulators) != MAX14577_REG_MAX);
|
||||
BUILD_BUG_ON(MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START +
|
||||
MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf !=
|
||||
MAX77836_REGULATOR_CURRENT_LIMIT_MAX);
|
||||
/* Valid charger current values must be provided for each chipset */
|
||||
BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM);
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(max14577_supported_regulators) != MAX14577_REGULATOR_NUM);
|
||||
BUILD_BUG_ON(ARRAY_SIZE(max77836_supported_regulators) != MAX77836_REGULATOR_NUM);
|
||||
|
||||
BUILD_BUG_ON(MAX77836_REGULATOR_LDO_VOLTAGE_MIN +
|
||||
(MAX77836_REGULATOR_LDO_VOLTAGE_STEP *
|
||||
(MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM - 1)) !=
|
||||
MAX77836_REGULATOR_LDO_VOLTAGE_MAX);
|
||||
|
||||
return platform_driver_register(&max14577_regulator_driver);
|
||||
}
|
||||
@ -264,6 +471,6 @@ static void __exit max14577_regulator_exit(void)
|
||||
module_exit(max14577_regulator_exit);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
|
||||
MODULE_DESCRIPTION("MAXIM 14577 regulator driver");
|
||||
MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:max14577-regulator");
|
||||
|
@ -185,8 +185,21 @@ struct extcon_specific_cable_nb {
|
||||
*/
|
||||
extern int extcon_dev_register(struct extcon_dev *edev);
|
||||
extern void extcon_dev_unregister(struct extcon_dev *edev);
|
||||
extern int devm_extcon_dev_register(struct device *dev,
|
||||
struct extcon_dev *edev);
|
||||
extern void devm_extcon_dev_unregister(struct device *dev,
|
||||
struct extcon_dev *edev);
|
||||
extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
|
||||
|
||||
/*
|
||||
* Following APIs control the memory of extcon device.
|
||||
*/
|
||||
extern struct extcon_dev *extcon_dev_allocate(const char **cables);
|
||||
extern void extcon_dev_free(struct extcon_dev *edev);
|
||||
extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
|
||||
const char **cables);
|
||||
extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev);
|
||||
|
||||
/*
|
||||
* get/set/update_state access the 32b encoded state value, which represents
|
||||
* states of all possible cables of the multistate port. For example, if one
|
||||
@ -254,6 +267,30 @@ static inline int extcon_dev_register(struct extcon_dev *edev)
|
||||
|
||||
static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
|
||||
|
||||
static inline int devm_extcon_dev_register(struct device *dev,
|
||||
struct extcon_dev *edev)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void devm_extcon_dev_unregister(struct device *dev,
|
||||
struct extcon_dev *edev) { }
|
||||
|
||||
static inline struct extcon_dev *extcon_dev_allocate(const char **cables)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline void extcon_dev_free(struct extcon_dev *edev) { }
|
||||
|
||||
static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
|
||||
const char **cables)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline void devm_extcon_dev_free(struct extcon_dev *edev) { }
|
||||
|
||||
static inline u32 extcon_get_state(struct extcon_dev *edev)
|
||||
{
|
||||
return 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* max14577-private.h - Common API for the Maxim 14577 internal sub chip
|
||||
* max14577-private.h - Common API for the Maxim 14577/77836 internal sub chip
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electrnoics
|
||||
* Copyright (C) 2014 Samsung Electrnoics
|
||||
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
*
|
||||
@ -22,9 +22,19 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MAX14577_REG_INVALID (0xff)
|
||||
#define I2C_ADDR_PMIC (0x46 >> 1)
|
||||
#define I2C_ADDR_MUIC (0x4A >> 1)
|
||||
#define I2C_ADDR_FG (0x6C >> 1)
|
||||
|
||||
/* Slave addr = 0x4A: Interrupt */
|
||||
enum maxim_device_type {
|
||||
MAXIM_DEVICE_TYPE_UNKNOWN = 0,
|
||||
MAXIM_DEVICE_TYPE_MAX14577,
|
||||
MAXIM_DEVICE_TYPE_MAX77836,
|
||||
|
||||
MAXIM_DEVICE_TYPE_NUM,
|
||||
};
|
||||
|
||||
/* Slave addr = 0x4A: MUIC and Charger */
|
||||
enum max14577_reg {
|
||||
MAX14577_REG_DEVICEID = 0x00,
|
||||
MAX14577_REG_INT1 = 0x01,
|
||||
@ -74,20 +84,22 @@ enum max14577_muic_charger_type {
|
||||
};
|
||||
|
||||
/* MAX14577 interrupts */
|
||||
#define INT1_ADC_MASK (0x1 << 0)
|
||||
#define INT1_ADCLOW_MASK (0x1 << 1)
|
||||
#define INT1_ADCERR_MASK (0x1 << 2)
|
||||
#define MAX14577_INT1_ADC_MASK BIT(0)
|
||||
#define MAX14577_INT1_ADCLOW_MASK BIT(1)
|
||||
#define MAX14577_INT1_ADCERR_MASK BIT(2)
|
||||
#define MAX77836_INT1_ADC1K_MASK BIT(3)
|
||||
|
||||
#define INT2_CHGTYP_MASK (0x1 << 0)
|
||||
#define INT2_CHGDETRUN_MASK (0x1 << 1)
|
||||
#define INT2_DCDTMR_MASK (0x1 << 2)
|
||||
#define INT2_DBCHG_MASK (0x1 << 3)
|
||||
#define INT2_VBVOLT_MASK (0x1 << 4)
|
||||
#define MAX14577_INT2_CHGTYP_MASK BIT(0)
|
||||
#define MAX14577_INT2_CHGDETRUN_MASK BIT(1)
|
||||
#define MAX14577_INT2_DCDTMR_MASK BIT(2)
|
||||
#define MAX14577_INT2_DBCHG_MASK BIT(3)
|
||||
#define MAX14577_INT2_VBVOLT_MASK BIT(4)
|
||||
#define MAX77836_INT2_VIDRM_MASK BIT(5)
|
||||
|
||||
#define INT3_EOC_MASK (0x1 << 0)
|
||||
#define INT3_CGMBC_MASK (0x1 << 1)
|
||||
#define INT3_OVP_MASK (0x1 << 2)
|
||||
#define INT3_MBCCHGERR_MASK (0x1 << 3)
|
||||
#define MAX14577_INT3_EOC_MASK BIT(0)
|
||||
#define MAX14577_INT3_CGMBC_MASK BIT(1)
|
||||
#define MAX14577_INT3_OVP_MASK BIT(2)
|
||||
#define MAX14577_INT3_MBCCHGERR_MASK BIT(3)
|
||||
|
||||
/* MAX14577 DEVICE ID register */
|
||||
#define DEVID_VENDORID_SHIFT 0
|
||||
@ -99,9 +111,11 @@ enum max14577_muic_charger_type {
|
||||
#define STATUS1_ADC_SHIFT 0
|
||||
#define STATUS1_ADCLOW_SHIFT 5
|
||||
#define STATUS1_ADCERR_SHIFT 6
|
||||
#define MAX77836_STATUS1_ADC1K_SHIFT 7
|
||||
#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT)
|
||||
#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT)
|
||||
#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT)
|
||||
#define STATUS1_ADCLOW_MASK BIT(STATUS1_ADCLOW_SHIFT)
|
||||
#define STATUS1_ADCERR_MASK BIT(STATUS1_ADCERR_SHIFT)
|
||||
#define MAX77836_STATUS1_ADC1K_MASK BIT(MAX77836_STATUS1_ADC1K_SHIFT)
|
||||
|
||||
/* MAX14577 STATUS2 register */
|
||||
#define STATUS2_CHGTYP_SHIFT 0
|
||||
@ -109,11 +123,13 @@ enum max14577_muic_charger_type {
|
||||
#define STATUS2_DCDTMR_SHIFT 4
|
||||
#define STATUS2_DBCHG_SHIFT 5
|
||||
#define STATUS2_VBVOLT_SHIFT 6
|
||||
#define MAX77836_STATUS2_VIDRM_SHIFT 7
|
||||
#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT)
|
||||
#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT)
|
||||
#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT)
|
||||
#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT)
|
||||
#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT)
|
||||
#define STATUS2_CHGDETRUN_MASK BIT(STATUS2_CHGDETRUN_SHIFT)
|
||||
#define STATUS2_DCDTMR_MASK BIT(STATUS2_DCDTMR_SHIFT)
|
||||
#define STATUS2_DBCHG_MASK BIT(STATUS2_DBCHG_SHIFT)
|
||||
#define STATUS2_VBVOLT_MASK BIT(STATUS2_VBVOLT_SHIFT)
|
||||
#define MAX77836_STATUS2_VIDRM_MASK BIT(MAX77836_STATUS2_VIDRM_SHIFT)
|
||||
|
||||
/* MAX14577 CONTROL1 register */
|
||||
#define COMN1SW_SHIFT 0
|
||||
@ -122,8 +138,8 @@ enum max14577_muic_charger_type {
|
||||
#define IDBEN_SHIFT 7
|
||||
#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT)
|
||||
#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT)
|
||||
#define MICEN_MASK (0x1 << MICEN_SHIFT)
|
||||
#define IDBEN_MASK (0x1 << IDBEN_SHIFT)
|
||||
#define MICEN_MASK BIT(MICEN_SHIFT)
|
||||
#define IDBEN_MASK BIT(IDBEN_SHIFT)
|
||||
#define CLEAR_IDBEN_MICEN_MASK (COMN1SW_MASK | COMP2SW_MASK)
|
||||
#define CTRL1_SW_USB ((1 << COMP2SW_SHIFT) \
|
||||
| (1 << COMN1SW_SHIFT))
|
||||
@ -143,14 +159,14 @@ enum max14577_muic_charger_type {
|
||||
#define CTRL2_ACCDET_SHIFT (5)
|
||||
#define CTRL2_USBCPINT_SHIFT (6)
|
||||
#define CTRL2_RCPS_SHIFT (7)
|
||||
#define CTRL2_LOWPWR_MASK (0x1 << CTRL2_LOWPWR_SHIFT)
|
||||
#define CTRL2_ADCEN_MASK (0x1 << CTRL2_ADCEN_SHIFT)
|
||||
#define CTRL2_CPEN_MASK (0x1 << CTRL2_CPEN_SHIFT)
|
||||
#define CTRL2_SFOUTASRT_MASK (0x1 << CTRL2_SFOUTASRT_SHIFT)
|
||||
#define CTRL2_SFOUTORD_MASK (0x1 << CTRL2_SFOUTORD_SHIFT)
|
||||
#define CTRL2_ACCDET_MASK (0x1 << CTRL2_ACCDET_SHIFT)
|
||||
#define CTRL2_USBCPINT_MASK (0x1 << CTRL2_USBCPINT_SHIFT)
|
||||
#define CTRL2_RCPS_MASK (0x1 << CTR2_RCPS_SHIFT)
|
||||
#define CTRL2_LOWPWR_MASK BIT(CTRL2_LOWPWR_SHIFT)
|
||||
#define CTRL2_ADCEN_MASK BIT(CTRL2_ADCEN_SHIFT)
|
||||
#define CTRL2_CPEN_MASK BIT(CTRL2_CPEN_SHIFT)
|
||||
#define CTRL2_SFOUTASRT_MASK BIT(CTRL2_SFOUTASRT_SHIFT)
|
||||
#define CTRL2_SFOUTORD_MASK BIT(CTRL2_SFOUTORD_SHIFT)
|
||||
#define CTRL2_ACCDET_MASK BIT(CTRL2_ACCDET_SHIFT)
|
||||
#define CTRL2_USBCPINT_MASK BIT(CTRL2_USBCPINT_SHIFT)
|
||||
#define CTRL2_RCPS_MASK BIT(CTRL2_RCPS_SHIFT)
|
||||
|
||||
#define CTRL2_CPEN1_LOWPWR0 ((1 << CTRL2_CPEN_SHIFT) | \
|
||||
(0 << CTRL2_LOWPWR_SHIFT))
|
||||
@ -198,14 +214,14 @@ enum max14577_charger_reg {
|
||||
#define CDETCTRL1_DBEXIT_SHIFT 5
|
||||
#define CDETCTRL1_DBIDLE_SHIFT 6
|
||||
#define CDETCTRL1_CDPDET_SHIFT 7
|
||||
#define CDETCTRL1_CHGDETEN_MASK (0x1 << CDETCTRL1_CHGDETEN_SHIFT)
|
||||
#define CDETCTRL1_CHGTYPMAN_MASK (0x1 << CDETCTRL1_CHGTYPMAN_SHIFT)
|
||||
#define CDETCTRL1_DCDEN_MASK (0x1 << CDETCTRL1_DCDEN_SHIFT)
|
||||
#define CDETCTRL1_DCD2SCT_MASK (0x1 << CDETCTRL1_DCD2SCT_SHIFT)
|
||||
#define CDETCTRL1_DCHKTM_MASK (0x1 << CDETCTRL1_DCHKTM_SHIFT)
|
||||
#define CDETCTRL1_DBEXIT_MASK (0x1 << CDETCTRL1_DBEXIT_SHIFT)
|
||||
#define CDETCTRL1_DBIDLE_MASK (0x1 << CDETCTRL1_DBIDLE_SHIFT)
|
||||
#define CDETCTRL1_CDPDET_MASK (0x1 << CDETCTRL1_CDPDET_SHIFT)
|
||||
#define CDETCTRL1_CHGDETEN_MASK BIT(CDETCTRL1_CHGDETEN_SHIFT)
|
||||
#define CDETCTRL1_CHGTYPMAN_MASK BIT(CDETCTRL1_CHGTYPMAN_SHIFT)
|
||||
#define CDETCTRL1_DCDEN_MASK BIT(CDETCTRL1_DCDEN_SHIFT)
|
||||
#define CDETCTRL1_DCD2SCT_MASK BIT(CDETCTRL1_DCD2SCT_SHIFT)
|
||||
#define CDETCTRL1_DCHKTM_MASK BIT(CDETCTRL1_DCHKTM_SHIFT)
|
||||
#define CDETCTRL1_DBEXIT_MASK BIT(CDETCTRL1_DBEXIT_SHIFT)
|
||||
#define CDETCTRL1_DBIDLE_MASK BIT(CDETCTRL1_DBIDLE_SHIFT)
|
||||
#define CDETCTRL1_CDPDET_MASK BIT(CDETCTRL1_CDPDET_SHIFT)
|
||||
|
||||
/* MAX14577 CHGCTRL1 register */
|
||||
#define CHGCTRL1_TCHW_SHIFT 4
|
||||
@ -213,9 +229,9 @@ enum max14577_charger_reg {
|
||||
|
||||
/* MAX14577 CHGCTRL2 register */
|
||||
#define CHGCTRL2_MBCHOSTEN_SHIFT 6
|
||||
#define CHGCTRL2_MBCHOSTEN_MASK (0x1 << CHGCTRL2_MBCHOSTEN_SHIFT)
|
||||
#define CHGCTRL2_MBCHOSTEN_MASK BIT(CHGCTRL2_MBCHOSTEN_SHIFT)
|
||||
#define CHGCTRL2_VCHGR_RC_SHIFT 7
|
||||
#define CHGCTRL2_VCHGR_RC_MASK (0x1 << CHGCTRL2_VCHGR_RC_SHIFT)
|
||||
#define CHGCTRL2_VCHGR_RC_MASK BIT(CHGCTRL2_VCHGR_RC_SHIFT)
|
||||
|
||||
/* MAX14577 CHGCTRL3 register */
|
||||
#define CHGCTRL3_MBCCVWRC_SHIFT 0
|
||||
@ -225,7 +241,7 @@ enum max14577_charger_reg {
|
||||
#define CHGCTRL4_MBCICHWRCH_SHIFT 0
|
||||
#define CHGCTRL4_MBCICHWRCH_MASK (0xf << CHGCTRL4_MBCICHWRCH_SHIFT)
|
||||
#define CHGCTRL4_MBCICHWRCL_SHIFT 4
|
||||
#define CHGCTRL4_MBCICHWRCL_MASK (0x1 << CHGCTRL4_MBCICHWRCL_SHIFT)
|
||||
#define CHGCTRL4_MBCICHWRCL_MASK BIT(CHGCTRL4_MBCICHWRCL_SHIFT)
|
||||
|
||||
/* MAX14577 CHGCTRL5 register */
|
||||
#define CHGCTRL5_EOCS_SHIFT 0
|
||||
@ -233,7 +249,7 @@ enum max14577_charger_reg {
|
||||
|
||||
/* MAX14577 CHGCTRL6 register */
|
||||
#define CHGCTRL6_AUTOSTOP_SHIFT 5
|
||||
#define CHGCTRL6_AUTOSTOP_MASK (0x1 << CHGCTRL6_AUTOSTOP_SHIFT)
|
||||
#define CHGCTRL6_AUTOSTOP_MASK BIT(CHGCTRL6_AUTOSTOP_SHIFT)
|
||||
|
||||
/* MAX14577 CHGCTRL7 register */
|
||||
#define CHGCTRL7_OTPCGHCVS_SHIFT 0
|
||||
@ -245,14 +261,111 @@ enum max14577_charger_reg {
|
||||
#define MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP 50000
|
||||
#define MAX14577_REGULATOR_CURRENT_LIMIT_MAX 950000
|
||||
|
||||
/* MAX77836 regulator current limits (as in CHGCTRL4 register), uA */
|
||||
#define MAX77836_REGULATOR_CURRENT_LIMIT_MIN 45000
|
||||
#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START 100000
|
||||
#define MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP 25000
|
||||
#define MAX77836_REGULATOR_CURRENT_LIMIT_MAX 475000
|
||||
|
||||
/* MAX14577 regulator SFOUT LDO voltage, fixed, uV */
|
||||
#define MAX14577_REGULATOR_SAFEOUT_VOLTAGE 4900000
|
||||
|
||||
/* MAX77836 regulator LDOx voltage, uV */
|
||||
#define MAX77836_REGULATOR_LDO_VOLTAGE_MIN 800000
|
||||
#define MAX77836_REGULATOR_LDO_VOLTAGE_MAX 3950000
|
||||
#define MAX77836_REGULATOR_LDO_VOLTAGE_STEP 50000
|
||||
#define MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM 64
|
||||
|
||||
/* Slave addr = 0x46: PMIC */
|
||||
enum max77836_pmic_reg {
|
||||
MAX77836_PMIC_REG_PMIC_ID = 0x20,
|
||||
MAX77836_PMIC_REG_PMIC_REV = 0x21,
|
||||
MAX77836_PMIC_REG_INTSRC = 0x22,
|
||||
MAX77836_PMIC_REG_INTSRC_MASK = 0x23,
|
||||
MAX77836_PMIC_REG_TOPSYS_INT = 0x24,
|
||||
MAX77836_PMIC_REG_TOPSYS_INT_MASK = 0x26,
|
||||
MAX77836_PMIC_REG_TOPSYS_STAT = 0x28,
|
||||
MAX77836_PMIC_REG_MRSTB_CNTL = 0x2A,
|
||||
MAX77836_PMIC_REG_LSCNFG = 0x2B,
|
||||
|
||||
MAX77836_LDO_REG_CNFG1_LDO1 = 0x51,
|
||||
MAX77836_LDO_REG_CNFG2_LDO1 = 0x52,
|
||||
MAX77836_LDO_REG_CNFG1_LDO2 = 0x53,
|
||||
MAX77836_LDO_REG_CNFG2_LDO2 = 0x54,
|
||||
MAX77836_LDO_REG_CNFG_LDO_BIAS = 0x55,
|
||||
|
||||
MAX77836_COMP_REG_COMP1 = 0x60,
|
||||
|
||||
MAX77836_PMIC_REG_END,
|
||||
};
|
||||
|
||||
#define MAX77836_INTSRC_MASK_TOP_INT_SHIFT 1
|
||||
#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT 3
|
||||
#define MAX77836_INTSRC_MASK_TOP_INT_MASK BIT(MAX77836_INTSRC_MASK_TOP_INT_SHIFT)
|
||||
#define MAX77836_INTSRC_MASK_MUIC_CHG_INT_MASK BIT(MAX77836_INTSRC_MASK_MUIC_CHG_INT_SHIFT)
|
||||
|
||||
/* MAX77836 PMIC interrupts */
|
||||
#define MAX77836_TOPSYS_INT_T120C_SHIFT 0
|
||||
#define MAX77836_TOPSYS_INT_T140C_SHIFT 1
|
||||
#define MAX77836_TOPSYS_INT_T120C_MASK BIT(MAX77836_TOPSYS_INT_T120C_SHIFT)
|
||||
#define MAX77836_TOPSYS_INT_T140C_MASK BIT(MAX77836_TOPSYS_INT_T140C_SHIFT)
|
||||
|
||||
/* LDO1/LDO2 CONFIG1 register */
|
||||
#define MAX77836_CNFG1_LDO_PWRMD_SHIFT 6
|
||||
#define MAX77836_CNFG1_LDO_TV_SHIFT 0
|
||||
#define MAX77836_CNFG1_LDO_PWRMD_MASK (0x3 << MAX77836_CNFG1_LDO_PWRMD_SHIFT)
|
||||
#define MAX77836_CNFG1_LDO_TV_MASK (0x3f << MAX77836_CNFG1_LDO_TV_SHIFT)
|
||||
|
||||
/* LDO1/LDO2 CONFIG2 register */
|
||||
#define MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT 7
|
||||
#define MAX77836_CNFG2_LDO_ALPMEN_SHIFT 6
|
||||
#define MAX77836_CNFG2_LDO_COMP_SHIFT 4
|
||||
#define MAX77836_CNFG2_LDO_POK_SHIFT 3
|
||||
#define MAX77836_CNFG2_LDO_ADE_SHIFT 1
|
||||
#define MAX77836_CNFG2_LDO_SS_SHIFT 0
|
||||
#define MAX77836_CNFG2_LDO_OVCLMPEN_MASK BIT(MAX77836_CNFG2_LDO_OVCLMPEN_SHIFT)
|
||||
#define MAX77836_CNFG2_LDO_ALPMEN_MASK BIT(MAX77836_CNFG2_LDO_ALPMEN_SHIFT)
|
||||
#define MAX77836_CNFG2_LDO_COMP_MASK (0x3 << MAX77836_CNFG2_LDO_COMP_SHIFT)
|
||||
#define MAX77836_CNFG2_LDO_POK_MASK BIT(MAX77836_CNFG2_LDO_POK_SHIFT)
|
||||
#define MAX77836_CNFG2_LDO_ADE_MASK BIT(MAX77836_CNFG2_LDO_ADE_SHIFT)
|
||||
#define MAX77836_CNFG2_LDO_SS_MASK BIT(MAX77836_CNFG2_LDO_SS_SHIFT)
|
||||
|
||||
/* Slave addr = 0x6C: Fuel-Gauge/Battery */
|
||||
enum max77836_fg_reg {
|
||||
MAX77836_FG_REG_VCELL_MSB = 0x02,
|
||||
MAX77836_FG_REG_VCELL_LSB = 0x03,
|
||||
MAX77836_FG_REG_SOC_MSB = 0x04,
|
||||
MAX77836_FG_REG_SOC_LSB = 0x05,
|
||||
MAX77836_FG_REG_MODE_H = 0x06,
|
||||
MAX77836_FG_REG_MODE_L = 0x07,
|
||||
MAX77836_FG_REG_VERSION_MSB = 0x08,
|
||||
MAX77836_FG_REG_VERSION_LSB = 0x09,
|
||||
MAX77836_FG_REG_HIBRT_H = 0x0A,
|
||||
MAX77836_FG_REG_HIBRT_L = 0x0B,
|
||||
MAX77836_FG_REG_CONFIG_H = 0x0C,
|
||||
MAX77836_FG_REG_CONFIG_L = 0x0D,
|
||||
MAX77836_FG_REG_VALRT_MIN = 0x14,
|
||||
MAX77836_FG_REG_VALRT_MAX = 0x15,
|
||||
MAX77836_FG_REG_CRATE_MSB = 0x16,
|
||||
MAX77836_FG_REG_CRATE_LSB = 0x17,
|
||||
MAX77836_FG_REG_VRESET = 0x18,
|
||||
MAX77836_FG_REG_FGID = 0x19,
|
||||
MAX77836_FG_REG_STATUS_H = 0x1A,
|
||||
MAX77836_FG_REG_STATUS_L = 0x1B,
|
||||
/*
|
||||
* TODO: TABLE registers
|
||||
* TODO: CMD register
|
||||
*/
|
||||
|
||||
MAX77836_FG_REG_END,
|
||||
};
|
||||
|
||||
enum max14577_irq {
|
||||
/* INT1 */
|
||||
MAX14577_IRQ_INT1_ADC,
|
||||
MAX14577_IRQ_INT1_ADCLOW,
|
||||
MAX14577_IRQ_INT1_ADCERR,
|
||||
MAX77836_IRQ_INT1_ADC1K,
|
||||
|
||||
/* INT2 */
|
||||
MAX14577_IRQ_INT2_CHGTYP,
|
||||
@ -260,6 +373,7 @@ enum max14577_irq {
|
||||
MAX14577_IRQ_INT2_DCDTMR,
|
||||
MAX14577_IRQ_INT2_DBCHG,
|
||||
MAX14577_IRQ_INT2_VBVOLT,
|
||||
MAX77836_IRQ_INT2_VIDRM,
|
||||
|
||||
/* INT3 */
|
||||
MAX14577_IRQ_INT3_EOC,
|
||||
@ -267,21 +381,25 @@ enum max14577_irq {
|
||||
MAX14577_IRQ_INT3_OVP,
|
||||
MAX14577_IRQ_INT3_MBCCHGERR,
|
||||
|
||||
/* TOPSYS_INT, only MAX77836 */
|
||||
MAX77836_IRQ_TOPSYS_T140C,
|
||||
MAX77836_IRQ_TOPSYS_T120C,
|
||||
|
||||
MAX14577_IRQ_NUM,
|
||||
};
|
||||
|
||||
struct max14577 {
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c; /* Slave addr = 0x4A */
|
||||
struct i2c_client *i2c_pmic; /* Slave addr = 0x46 */
|
||||
enum maxim_device_type dev_type;
|
||||
|
||||
struct regmap *regmap;
|
||||
struct regmap *regmap; /* For MUIC and Charger */
|
||||
struct regmap *regmap_pmic;
|
||||
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
struct regmap_irq_chip_data *irq_data; /* For MUIC and Charger */
|
||||
struct regmap_irq_chip_data *irq_data_pmic;
|
||||
int irq;
|
||||
|
||||
/* Device ID */
|
||||
u8 vendor_id; /* Vendor Identification */
|
||||
u8 device_id; /* Chip Version */
|
||||
};
|
||||
|
||||
/* MAX14577 shared regmap API function */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* max14577.h - Driver for the Maxim 14577
|
||||
* max14577.h - Driver for the Maxim 14577/77836
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electrnoics
|
||||
* Copyright (C) 2014 Samsung Electrnoics
|
||||
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
*
|
||||
@ -20,6 +20,9 @@
|
||||
* MAX14577 has MUIC, Charger devices.
|
||||
* The devices share the same I2C bus and interrupt line
|
||||
* included in this mfd driver.
|
||||
*
|
||||
* MAX77836 has additional PMIC and Fuel-Gauge on different I2C slave
|
||||
* addresses.
|
||||
*/
|
||||
|
||||
#ifndef __MAX14577_H__
|
||||
@ -32,7 +35,17 @@ enum max14577_regulators {
|
||||
MAX14577_SAFEOUT = 0,
|
||||
MAX14577_CHARGER,
|
||||
|
||||
MAX14577_REG_MAX,
|
||||
MAX14577_REGULATOR_NUM,
|
||||
};
|
||||
|
||||
/* MAX77836 regulator IDs */
|
||||
enum max77836_regulators {
|
||||
MAX77836_SAFEOUT = 0,
|
||||
MAX77836_CHARGER,
|
||||
MAX77836_LDO1,
|
||||
MAX77836_LDO2,
|
||||
|
||||
MAX77836_REGULATOR_NUM,
|
||||
};
|
||||
|
||||
struct max14577_regulator_platform_data {
|
||||
|
@ -415,7 +415,7 @@ struct palmas_usb {
|
||||
struct palmas *palmas;
|
||||
struct device *dev;
|
||||
|
||||
struct extcon_dev edev;
|
||||
struct extcon_dev *edev;
|
||||
|
||||
int id_otg_irq;
|
||||
int id_irq;
|
||||
|
Loading…
Reference in New Issue
Block a user