Commit e349c910 authored by Krzysztof Kozlowski's avatar Krzysztof Kozlowski Committed by Lee Jones

mfd/rtc: s5m: Do not allocate RTC I2C dummy and regmap for unsupported chipsets

The rtc-s5m driver does not support all of S2M and S5M chipsets
supported by main MFD sec-core driver. For such chipsets unsupported by
rtc-s5m, the MFD sec-core driver initialized regmap with default config.
This config in such cases wouldn't work at all.

The main MFD sec-core driver shouldn't initialize regmap for child
drivers which is not used by them and even not valid.

Move the allocation of RTC I2C dummy device and initialization of RTC
regmap from main MFD sec-core driver to the rtc-s5m driver. The rtc-s5m
driver will use proper regmap config for supported devices.
Signed-off-by: default avatarKrzysztof Kozlowski <k.kozlowski@samsung.com>
Acked-by: default avatarAlessandro Zummo <a.zummo@towertech.it>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
parent a865a589
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h> #include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/rtc.h>
#include <linux/mfd/samsung/s2mpa01.h> #include <linux/mfd/samsung/s2mpa01.h>
#include <linux/mfd/samsung/s2mps11.h> #include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s2mps14.h> #include <linux/mfd/samsung/s2mps14.h>
...@@ -196,20 +195,6 @@ static const struct regmap_config s5m8767_regmap_config = { ...@@ -196,20 +195,6 @@ static const struct regmap_config s5m8767_regmap_config = {
.cache_type = REGCACHE_FLAT, .cache_type = REGCACHE_FLAT,
}; };
static const struct regmap_config s5m_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = SEC_RTC_REG_MAX,
};
static const struct regmap_config s2mps14_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = S2MPS_RTC_REG_MAX,
};
#ifdef CONFIG_OF #ifdef CONFIG_OF
/* /*
* Only the common platform data elements for s5m8767 are parsed here from the * Only the common platform data elements for s5m8767 are parsed here from the
...@@ -264,7 +249,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, ...@@ -264,7 +249,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
const struct regmap_config *regmap, *regmap_rtc; const struct regmap_config *regmap;
struct sec_pmic_dev *sec_pmic; struct sec_pmic_dev *sec_pmic;
int ret; int ret;
...@@ -298,39 +283,21 @@ static int sec_pmic_probe(struct i2c_client *i2c, ...@@ -298,39 +283,21 @@ static int sec_pmic_probe(struct i2c_client *i2c,
switch (sec_pmic->device_type) { switch (sec_pmic->device_type) {
case S2MPA01: case S2MPA01:
regmap = &s2mpa01_regmap_config; regmap = &s2mpa01_regmap_config;
/*
* The rtc-s5m driver does not support S2MPA01 and there
* is no mfd_cell for S2MPA01 RTC device.
* However we must pass something to devm_regmap_init_i2c()
* so use S5M-like regmap config even though it wouldn't work.
*/
regmap_rtc = &s5m_rtc_regmap_config;
break; break;
case S2MPS11X: case S2MPS11X:
regmap = &s2mps11_regmap_config; regmap = &s2mps11_regmap_config;
/*
* The rtc-s5m driver does not support S2MPS11 and there
* is no mfd_cell for S2MPS11 RTC device.
* However we must pass something to devm_regmap_init_i2c()
* so use S5M-like regmap config even though it wouldn't work.
*/
regmap_rtc = &s5m_rtc_regmap_config;
break; break;
case S2MPS14X: case S2MPS14X:
regmap = &s2mps14_regmap_config; regmap = &s2mps14_regmap_config;
regmap_rtc = &s2mps14_rtc_regmap_config;
break; break;
case S5M8763X: case S5M8763X:
regmap = &s5m8763_regmap_config; regmap = &s5m8763_regmap_config;
regmap_rtc = &s5m_rtc_regmap_config;
break; break;
case S5M8767X: case S5M8767X:
regmap = &s5m8767_regmap_config; regmap = &s5m8767_regmap_config;
regmap_rtc = &s5m_rtc_regmap_config;
break; break;
default: default:
regmap = &sec_regmap_config; regmap = &sec_regmap_config;
regmap_rtc = &s5m_rtc_regmap_config;
break; break;
} }
...@@ -342,21 +309,6 @@ static int sec_pmic_probe(struct i2c_client *i2c, ...@@ -342,21 +309,6 @@ static int sec_pmic_probe(struct i2c_client *i2c,
return ret; return ret;
} }
sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
if (!sec_pmic->rtc) {
dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n");
return -ENODEV;
}
i2c_set_clientdata(sec_pmic->rtc, sec_pmic);
sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc);
if (IS_ERR(sec_pmic->regmap_rtc)) {
ret = PTR_ERR(sec_pmic->regmap_rtc);
dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
ret);
goto err_regmap_rtc;
}
if (pdata && pdata->cfg_pmic_irq) if (pdata && pdata->cfg_pmic_irq)
pdata->cfg_pmic_irq(); pdata->cfg_pmic_irq();
...@@ -403,8 +355,6 @@ static int sec_pmic_probe(struct i2c_client *i2c, ...@@ -403,8 +355,6 @@ static int sec_pmic_probe(struct i2c_client *i2c,
err_mfd: err_mfd:
sec_irq_exit(sec_pmic); sec_irq_exit(sec_pmic);
err_regmap_rtc:
i2c_unregister_device(sec_pmic->rtc);
return ret; return ret;
} }
...@@ -414,7 +364,6 @@ static int sec_pmic_remove(struct i2c_client *i2c) ...@@ -414,7 +364,6 @@ static int sec_pmic_remove(struct i2c_client *i2c)
mfd_remove_devices(sec_pmic->dev); mfd_remove_devices(sec_pmic->dev);
sec_irq_exit(sec_pmic); sec_irq_exit(sec_pmic);
i2c_unregister_device(sec_pmic->rtc);
return 0; return 0;
} }
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
struct s5m_rtc_info { struct s5m_rtc_info {
struct device *dev; struct device *dev;
struct i2c_client *i2c;
struct sec_pmic_dev *s5m87xx; struct sec_pmic_dev *s5m87xx;
struct regmap *regmap; struct regmap *regmap;
struct rtc_device *rtc_dev; struct rtc_device *rtc_dev;
...@@ -49,6 +50,20 @@ struct s5m_rtc_info { ...@@ -49,6 +50,20 @@ struct s5m_rtc_info {
bool wtsr_smpl; bool wtsr_smpl;
}; };
static const struct regmap_config s5m_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = SEC_RTC_REG_MAX,
};
static const struct regmap_config s2mps14_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = S2MPS_RTC_REG_MAX,
};
static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm, static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm,
int rtc_24hr_mode) int rtc_24hr_mode)
{ {
...@@ -554,6 +569,7 @@ static int s5m_rtc_probe(struct platform_device *pdev) ...@@ -554,6 +569,7 @@ static int s5m_rtc_probe(struct platform_device *pdev)
struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent); struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent);
struct sec_platform_data *pdata = s5m87xx->pdata; struct sec_platform_data *pdata = s5m87xx->pdata;
struct s5m_rtc_info *info; struct s5m_rtc_info *info;
const struct regmap_config *regmap_cfg;
int ret; int ret;
if (!pdata) { if (!pdata) {
...@@ -565,9 +581,37 @@ static int s5m_rtc_probe(struct platform_device *pdev) ...@@ -565,9 +581,37 @@ static int s5m_rtc_probe(struct platform_device *pdev)
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
switch (pdata->device_type) {
case S2MPS14X:
regmap_cfg = &s2mps14_rtc_regmap_config;
break;
case S5M8763X:
regmap_cfg = &s5m_rtc_regmap_config;
break;
case S5M8767X:
regmap_cfg = &s5m_rtc_regmap_config;
break;
default:
dev_err(&pdev->dev, "Device type is not supported by RTC driver\n");
return -ENODEV;
}
info->i2c = i2c_new_dummy(s5m87xx->i2c->adapter, RTC_I2C_ADDR);
if (!info->i2c) {
dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n");
return -ENODEV;
}
info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg);
if (IS_ERR(info->regmap)) {
ret = PTR_ERR(info->regmap);
dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n",
ret);
goto err;
}
info->dev = &pdev->dev; info->dev = &pdev->dev;
info->s5m87xx = s5m87xx; info->s5m87xx = s5m87xx;
info->regmap = s5m87xx->regmap_rtc;
info->device_type = s5m87xx->device_type; info->device_type = s5m87xx->device_type;
info->wtsr_smpl = s5m87xx->wtsr_smpl; info->wtsr_smpl = s5m87xx->wtsr_smpl;
...@@ -585,7 +629,7 @@ static int s5m_rtc_probe(struct platform_device *pdev) ...@@ -585,7 +629,7 @@ static int s5m_rtc_probe(struct platform_device *pdev)
default: default:
ret = -EINVAL; ret = -EINVAL;
dev_err(&pdev->dev, "Unsupported device type: %d\n", ret); dev_err(&pdev->dev, "Unsupported device type: %d\n", ret);
return ret; goto err;
} }
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
...@@ -602,15 +646,24 @@ static int s5m_rtc_probe(struct platform_device *pdev) ...@@ -602,15 +646,24 @@ static int s5m_rtc_probe(struct platform_device *pdev)
info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc", info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc",
&s5m_rtc_ops, THIS_MODULE); &s5m_rtc_ops, THIS_MODULE);
if (IS_ERR(info->rtc_dev)) if (IS_ERR(info->rtc_dev)) {
return PTR_ERR(info->rtc_dev); ret = PTR_ERR(info->rtc_dev);
goto err;
}
ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
s5m_rtc_alarm_irq, 0, "rtc-alarm0", s5m_rtc_alarm_irq, 0, "rtc-alarm0",
info); info);
if (ret < 0) if (ret < 0) {
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
info->irq, ret); info->irq, ret);
goto err;
}
return 0;
err:
i2c_unregister_device(info->i2c);
return ret; return ret;
} }
...@@ -639,6 +692,17 @@ static void s5m_rtc_shutdown(struct platform_device *pdev) ...@@ -639,6 +692,17 @@ static void s5m_rtc_shutdown(struct platform_device *pdev)
s5m_rtc_enable_smpl(info, false); s5m_rtc_enable_smpl(info, false);
} }
static int s5m_rtc_remove(struct platform_device *pdev)
{
struct s5m_rtc_info *info = platform_get_drvdata(pdev);
/* Perform also all shutdown steps when removing */
s5m_rtc_shutdown(pdev);
i2c_unregister_device(info->i2c);
return 0;
}
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int s5m_rtc_resume(struct device *dev) static int s5m_rtc_resume(struct device *dev)
{ {
...@@ -676,6 +740,7 @@ static struct platform_driver s5m_rtc_driver = { ...@@ -676,6 +740,7 @@ static struct platform_driver s5m_rtc_driver = {
.pm = &s5m_rtc_pm_ops, .pm = &s5m_rtc_pm_ops,
}, },
.probe = s5m_rtc_probe, .probe = s5m_rtc_probe,
.remove = s5m_rtc_remove,
.shutdown = s5m_rtc_shutdown, .shutdown = s5m_rtc_shutdown,
.id_table = s5m_rtc_id, .id_table = s5m_rtc_id,
}; };
......
...@@ -28,7 +28,6 @@ enum sec_device_type { ...@@ -28,7 +28,6 @@ enum sec_device_type {
* @dev: master device of the chip (can be used to access platform data) * @dev: master device of the chip (can be used to access platform data)
* @pdata: pointer to private data used to pass platform data to child * @pdata: pointer to private data used to pass platform data to child
* @i2c: i2c client private data for regulator * @i2c: i2c client private data for regulator
* @rtc: i2c client private data for rtc
* @iolock: mutex for serializing io access * @iolock: mutex for serializing io access
* @irqlock: mutex for buslock * @irqlock: mutex for buslock
* @irq_base: base IRQ number for sec-pmic, required for IRQs * @irq_base: base IRQ number for sec-pmic, required for IRQs
...@@ -42,9 +41,7 @@ struct sec_pmic_dev { ...@@ -42,9 +41,7 @@ struct sec_pmic_dev {
struct device *dev; struct device *dev;
struct sec_platform_data *pdata; struct sec_platform_data *pdata;
struct regmap *regmap_pmic; struct regmap *regmap_pmic;
struct regmap *regmap_rtc;
struct i2c_client *i2c; struct i2c_client *i2c;
struct i2c_client *rtc;
int device_type; int device_type;
int irq_base; int irq_base;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment