0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/delay.h>
0013 #include <linux/uaccess.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/time.h>
0016 #include <linux/watchdog.h>
0017 #include <linux/types.h>
0018 #include <linux/kernel.h>
0019 #include <linux/jiffies.h>
0020
0021 #include <linux/mfd/da9052/reg.h>
0022 #include <linux/mfd/da9052/da9052.h>
0023
0024 #define DA9052_DEF_TIMEOUT 4
0025 #define DA9052_TWDMIN 256
0026
0027 struct da9052_wdt_data {
0028 struct watchdog_device wdt;
0029 struct da9052 *da9052;
0030 unsigned long jpast;
0031 };
0032
0033 static const struct {
0034 u8 reg_val;
0035 int time;
0036 } da9052_wdt_maps[] = {
0037 { 1, 2 },
0038 { 2, 4 },
0039 { 3, 8 },
0040 { 4, 16 },
0041 { 5, 32 },
0042 { 5, 33 },
0043 { 6, 65 },
0044 { 6, 66 },
0045 { 7, 131 },
0046 };
0047
0048
0049 static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
0050 unsigned int timeout)
0051 {
0052 struct da9052_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
0053 struct da9052 *da9052 = driver_data->da9052;
0054 int ret, i;
0055
0056
0057
0058
0059
0060 ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
0061 DA9052_CONTROLD_TWDSCALE, 0);
0062 if (ret < 0) {
0063 dev_err(da9052->dev, "Failed to disable watchdog bit, %d\n",
0064 ret);
0065 return ret;
0066 }
0067 if (timeout) {
0068
0069
0070
0071
0072 udelay(150);
0073
0074
0075 for (i = 0; i < ARRAY_SIZE(da9052_wdt_maps); i++)
0076 if (da9052_wdt_maps[i].time == timeout)
0077 break;
0078
0079 if (i == ARRAY_SIZE(da9052_wdt_maps))
0080 ret = -EINVAL;
0081 else
0082 ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
0083 DA9052_CONTROLD_TWDSCALE,
0084 da9052_wdt_maps[i].reg_val);
0085 if (ret < 0) {
0086 dev_err(da9052->dev,
0087 "Failed to update timescale bit, %d\n", ret);
0088 return ret;
0089 }
0090
0091 wdt_dev->timeout = timeout;
0092 driver_data->jpast = jiffies;
0093 }
0094
0095 return 0;
0096 }
0097
0098 static int da9052_wdt_start(struct watchdog_device *wdt_dev)
0099 {
0100 return da9052_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
0101 }
0102
0103 static int da9052_wdt_stop(struct watchdog_device *wdt_dev)
0104 {
0105 return da9052_wdt_set_timeout(wdt_dev, 0);
0106 }
0107
0108 static int da9052_wdt_ping(struct watchdog_device *wdt_dev)
0109 {
0110 struct da9052_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
0111 struct da9052 *da9052 = driver_data->da9052;
0112 unsigned long msec, jnow = jiffies;
0113 int ret;
0114
0115
0116
0117
0118
0119 msec = (jnow - driver_data->jpast) * 1000/HZ;
0120 if (msec < DA9052_TWDMIN)
0121 mdelay(msec);
0122
0123
0124 ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
0125 DA9052_CONTROLD_WATCHDOG, 1 << 7);
0126 if (ret < 0)
0127 return ret;
0128
0129
0130
0131
0132
0133 return da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
0134 DA9052_CONTROLD_WATCHDOG, 0 << 7);
0135 }
0136
0137 static const struct watchdog_info da9052_wdt_info = {
0138 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
0139 .identity = "DA9052 Watchdog",
0140 };
0141
0142 static const struct watchdog_ops da9052_wdt_ops = {
0143 .owner = THIS_MODULE,
0144 .start = da9052_wdt_start,
0145 .stop = da9052_wdt_stop,
0146 .ping = da9052_wdt_ping,
0147 .set_timeout = da9052_wdt_set_timeout,
0148 };
0149
0150
0151 static int da9052_wdt_probe(struct platform_device *pdev)
0152 {
0153 struct device *dev = &pdev->dev;
0154 struct da9052 *da9052 = dev_get_drvdata(dev->parent);
0155 struct da9052_wdt_data *driver_data;
0156 struct watchdog_device *da9052_wdt;
0157 int ret;
0158
0159 driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);
0160 if (!driver_data)
0161 return -ENOMEM;
0162 driver_data->da9052 = da9052;
0163
0164 da9052_wdt = &driver_data->wdt;
0165
0166 da9052_wdt->timeout = DA9052_DEF_TIMEOUT;
0167 da9052_wdt->info = &da9052_wdt_info;
0168 da9052_wdt->ops = &da9052_wdt_ops;
0169 da9052_wdt->parent = dev;
0170 watchdog_set_drvdata(da9052_wdt, driver_data);
0171
0172 ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
0173 DA9052_CONTROLD_TWDSCALE, 0);
0174 if (ret < 0) {
0175 dev_err(dev, "Failed to disable watchdog bits, %d\n", ret);
0176 return ret;
0177 }
0178
0179 return devm_watchdog_register_device(dev, &driver_data->wdt);
0180 }
0181
0182 static struct platform_driver da9052_wdt_driver = {
0183 .probe = da9052_wdt_probe,
0184 .driver = {
0185 .name = "da9052-watchdog",
0186 },
0187 };
0188
0189 module_platform_driver(da9052_wdt_driver);
0190
0191 MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
0192 MODULE_DESCRIPTION("DA9052 SM Device Driver");
0193 MODULE_LICENSE("GPL");
0194 MODULE_ALIAS("platform:da9052-watchdog");