| 1 | |
| 2 | |
| 3 |
|
| 4 | #include <linux/bcd.h>
|
| 5 | #include <linux/clk-provider.h>
|
| 6 | #include <linux/err.h>
|
| 7 | #include <linux/i2c.h>
|
| 8 | #include <linux/module.h>
|
| 9 | #include <linux/of.h>
|
| 10 | #include <linux/rtc.h>
|
| 11 | #include <linux/slab.h>
|
| 12 |
|
| 13 | #define NCT3018Y_REG_SC 0x00
|
| 14 | #define NCT3018Y_REG_SCA 0x01
|
| 15 | #define NCT3018Y_REG_MN 0x02
|
| 16 | #define NCT3018Y_REG_MNA 0x03
|
| 17 | #define NCT3018Y_REG_HR 0x04
|
| 18 | #define NCT3018Y_REG_HRA 0x05
|
| 19 | #define NCT3018Y_REG_DW 0x06
|
| 20 | #define NCT3018Y_REG_DM 0x07
|
| 21 | #define NCT3018Y_REG_MO 0x08
|
| 22 | #define NCT3018Y_REG_YR 0x09
|
| 23 | #define NCT3018Y_REG_CTRL 0x0A
|
| 24 | #define NCT3018Y_REG_ST 0x0B
|
| 25 | #define NCT3018Y_REG_CLKO 0x0C
|
| 26 | #define NCT3018Y_REG_PART 0x21
|
| 27 |
|
| 28 | #define NCT3018Y_BIT_AF BIT(7)
|
| 29 | #define NCT3018Y_BIT_ST BIT(7)
|
| 30 | #define NCT3018Y_BIT_DM BIT(6)
|
| 31 | #define NCT3018Y_BIT_HF BIT(5)
|
| 32 | #define NCT3018Y_BIT_DSM BIT(4)
|
| 33 | #define NCT3018Y_BIT_AIE BIT(3)
|
| 34 | #define NCT3018Y_BIT_OFIE BIT(2)
|
| 35 | #define NCT3018Y_BIT_CIE BIT(1)
|
| 36 | #define NCT3018Y_BIT_TWO BIT(0)
|
| 37 |
|
| 38 | #define NCT3018Y_REG_BAT_MASK 0x07
|
| 39 | #define NCT3018Y_REG_CLKO_F_MASK 0x03
|
| 40 | #define NCT3018Y_REG_CLKO_CKE 0x80
|
| 41 | #define NCT3018Y_REG_PART_NCT3018Y 0x02
|
| 42 |
|
| 43 | struct nct3018y {
|
| 44 | struct rtc_device *rtc;
|
| 45 | struct i2c_client *client;
|
| 46 | int part_num;
|
| 47 | #ifdef CONFIG_COMMON_CLK
|
| 48 | struct clk_hw clkout_hw;
|
| 49 | #endif
|
| 50 | };
|
| 51 |
|
| 52 | static int nct3018y_set_alarm_mode(struct i2c_client *client, bool on)
|
| 53 | {
|
| 54 | int err, flags;
|
| 55 |
|
| 56 | dev_dbg(&client->dev, "%s:on:%d\n", __func__, on);
|
| 57 |
|
| 58 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CTRL);
|
| 59 | if (flags < 0) {
|
| 60 | dev_dbg(&client->dev,
|
| 61 | "Failed to read NCT3018Y_REG_CTRL\n");
|
| 62 | return flags;
|
| 63 | }
|
| 64 |
|
| 65 | if (on)
|
| 66 | flags |= NCT3018Y_BIT_AIE;
|
| 67 | else
|
| 68 | flags &= ~NCT3018Y_BIT_AIE;
|
| 69 |
|
| 70 | flags |= NCT3018Y_BIT_CIE;
|
| 71 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
|
| 72 | if (err < 0) {
|
| 73 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL\n");
|
| 74 | return err;
|
| 75 | }
|
| 76 |
|
| 77 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_ST);
|
| 78 | if (flags < 0) {
|
| 79 | dev_dbg(&client->dev,
|
| 80 | "Failed to read NCT3018Y_REG_ST\n");
|
| 81 | return flags;
|
| 82 | }
|
| 83 |
|
| 84 | flags &= ~(NCT3018Y_BIT_AF);
|
| 85 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_ST, flags);
|
| 86 | if (err < 0) {
|
| 87 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_ST\n");
|
| 88 | return err;
|
| 89 | }
|
| 90 |
|
| 91 | return 0;
|
| 92 | }
|
| 93 |
|
| 94 | static int nct3018y_get_alarm_mode(struct i2c_client *client, unsigned char *alarm_enable,
|
| 95 | unsigned char *alarm_flag)
|
| 96 | {
|
| 97 | int flags;
|
| 98 |
|
| 99 | if (alarm_enable) {
|
| 100 | dev_dbg(&client->dev, "%s:NCT3018Y_REG_CTRL\n", __func__);
|
| 101 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CTRL);
|
| 102 | if (flags < 0)
|
| 103 | return flags;
|
| 104 | *alarm_enable = flags & NCT3018Y_BIT_AIE;
|
| 105 | dev_dbg(&client->dev, "%s:alarm_enable:%x\n", __func__, *alarm_enable);
|
| 106 |
|
| 107 | }
|
| 108 |
|
| 109 | if (alarm_flag) {
|
| 110 | dev_dbg(&client->dev, "%s:NCT3018Y_REG_ST\n", __func__);
|
| 111 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_ST);
|
| 112 | if (flags < 0)
|
| 113 | return flags;
|
| 114 | *alarm_flag = flags & NCT3018Y_BIT_AF;
|
| 115 | dev_dbg(&client->dev, "%s:alarm_flag:%x\n", __func__, *alarm_flag);
|
| 116 | }
|
| 117 |
|
| 118 | return 0;
|
| 119 | }
|
| 120 |
|
| 121 | static irqreturn_t nct3018y_irq(int irq, void *dev_id)
|
| 122 | {
|
| 123 | struct nct3018y *nct3018y = i2c_get_clientdata(dev_id);
|
| 124 | struct i2c_client *client = nct3018y->client;
|
| 125 | int err;
|
| 126 | unsigned char alarm_flag;
|
| 127 | unsigned char alarm_enable;
|
| 128 |
|
| 129 | dev_dbg(&client->dev, "%s:irq:%d\n", __func__, irq);
|
| 130 | err = nct3018y_get_alarm_mode(nct3018y->client, &alarm_enable, &alarm_flag);
|
| 131 | if (err)
|
| 132 | return IRQ_NONE;
|
| 133 |
|
| 134 | if (alarm_flag) {
|
| 135 | dev_dbg(&client->dev, "%s:alarm flag:%x\n",
|
| 136 | __func__, alarm_flag);
|
| 137 | rtc_update_irq(nct3018y->rtc, 1, RTC_IRQF | RTC_AF);
|
| 138 | nct3018y_set_alarm_mode(nct3018y->client, 0);
|
| 139 | dev_dbg(&client->dev, "%s:IRQ_HANDLED\n", __func__);
|
| 140 | return IRQ_HANDLED;
|
| 141 | }
|
| 142 |
|
| 143 | return IRQ_NONE;
|
| 144 | }
|
| 145 |
|
| 146 | |
| 147 | * In the routines that deal directly with the nct3018y hardware, we use
|
| 148 | * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
|
| 149 |
|
| 150 | static int nct3018y_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
| 151 | {
|
| 152 | struct i2c_client *client = to_i2c_client(dev);
|
| 153 | unsigned char buf[10];
|
| 154 | int err;
|
| 155 |
|
| 156 | err = i2c_smbus_read_i2c_block_data(client, NCT3018Y_REG_ST, 1, buf);
|
| 157 | if (err < 0)
|
| 158 | return err;
|
| 159 |
|
| 160 | if (!buf[0]) {
|
| 161 | dev_dbg(&client->dev, " voltage <=1.7, date/time is not reliable.\n");
|
| 162 | return -EINVAL;
|
| 163 | }
|
| 164 |
|
| 165 | err = i2c_smbus_read_i2c_block_data(client, NCT3018Y_REG_SC, sizeof(buf), buf);
|
| 166 | if (err < 0)
|
| 167 | return err;
|
| 168 |
|
| 169 | tm->tm_sec = bcd2bin(buf[0] & 0x7F);
|
| 170 | tm->tm_min = bcd2bin(buf[2] & 0x7F);
|
| 171 | tm->tm_hour = bcd2bin(buf[4] & 0x3F);
|
| 172 | tm->tm_wday = buf[6] & 0x07;
|
| 173 | tm->tm_mday = bcd2bin(buf[7] & 0x3F);
|
| 174 | tm->tm_mon = bcd2bin(buf[8] & 0x1F) - 1;
|
| 175 | tm->tm_year = bcd2bin(buf[9]) + 100;
|
| 176 |
|
| 177 | return 0;
|
| 178 | }
|
| 179 |
|
| 180 | static int nct3018y_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
| 181 | {
|
| 182 | struct i2c_client *client = to_i2c_client(dev);
|
| 183 | struct nct3018y *nct3018y = dev_get_drvdata(dev);
|
| 184 | unsigned char buf[4] = {0};
|
| 185 | int err, flags;
|
| 186 | int restore_flags = 0;
|
| 187 |
|
| 188 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CTRL);
|
| 189 | if (flags < 0) {
|
| 190 | dev_dbg(&client->dev, "Failed to read NCT3018Y_REG_CTRL.\n");
|
| 191 | return flags;
|
| 192 | }
|
| 193 |
|
| 194 |
|
| 195 | if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y && !(flags & NCT3018Y_BIT_TWO)) {
|
| 196 | restore_flags = 1;
|
| 197 | flags |= NCT3018Y_BIT_TWO;
|
| 198 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
|
| 199 | if (err < 0) {
|
| 200 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
|
| 201 | return err;
|
| 202 | }
|
| 203 | }
|
| 204 |
|
| 205 | buf[0] = bin2bcd(tm->tm_sec);
|
| 206 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_SC, buf[0]);
|
| 207 | if (err < 0) {
|
| 208 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_SC\n");
|
| 209 | return err;
|
| 210 | }
|
| 211 |
|
| 212 | buf[0] = bin2bcd(tm->tm_min);
|
| 213 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_MN, buf[0]);
|
| 214 | if (err < 0) {
|
| 215 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_MN\n");
|
| 216 | return err;
|
| 217 | }
|
| 218 |
|
| 219 | buf[0] = bin2bcd(tm->tm_hour);
|
| 220 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_HR, buf[0]);
|
| 221 | if (err < 0) {
|
| 222 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_HR\n");
|
| 223 | return err;
|
| 224 | }
|
| 225 |
|
| 226 | buf[0] = tm->tm_wday & 0x07;
|
| 227 | buf[1] = bin2bcd(tm->tm_mday);
|
| 228 | buf[2] = bin2bcd(tm->tm_mon + 1);
|
| 229 | buf[3] = bin2bcd(tm->tm_year - 100);
|
| 230 | err = i2c_smbus_write_i2c_block_data(client, NCT3018Y_REG_DW,
|
| 231 | sizeof(buf), buf);
|
| 232 | if (err < 0) {
|
| 233 | dev_dbg(&client->dev, "Unable to write for day and mon and year\n");
|
| 234 | return -EIO;
|
| 235 | }
|
| 236 |
|
| 237 |
|
| 238 | if (restore_flags) {
|
| 239 | if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y)
|
| 240 | flags &= ~NCT3018Y_BIT_TWO;
|
| 241 |
|
| 242 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
|
| 243 | if (err < 0) {
|
| 244 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
|
| 245 | return err;
|
| 246 | }
|
| 247 | }
|
| 248 |
|
| 249 | return err;
|
| 250 | }
|
| 251 |
|
| 252 | static int nct3018y_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
| 253 | {
|
| 254 | struct i2c_client *client = to_i2c_client(dev);
|
| 255 | unsigned char buf[5];
|
| 256 | int err;
|
| 257 |
|
| 258 | err = i2c_smbus_read_i2c_block_data(client, NCT3018Y_REG_SCA,
|
| 259 | sizeof(buf), buf);
|
| 260 | if (err < 0) {
|
| 261 | dev_dbg(&client->dev, "Unable to read date\n");
|
| 262 | return -EIO;
|
| 263 | }
|
| 264 |
|
| 265 | dev_dbg(&client->dev, "%s: raw data is sec=%02x, min=%02x hr=%02x\n",
|
| 266 | __func__, buf[0], buf[2], buf[4]);
|
| 267 |
|
| 268 | tm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
|
| 269 | tm->time.tm_min = bcd2bin(buf[2] & 0x7F);
|
| 270 | tm->time.tm_hour = bcd2bin(buf[4] & 0x3F);
|
| 271 |
|
| 272 | err = nct3018y_get_alarm_mode(client, &tm->enabled, &tm->pending);
|
| 273 | if (err < 0)
|
| 274 | return err;
|
| 275 |
|
| 276 | dev_dbg(&client->dev, "%s:s=%d m=%d, hr=%d, enabled=%d, pending=%d\n",
|
| 277 | __func__, tm->time.tm_sec, tm->time.tm_min,
|
| 278 | tm->time.tm_hour, tm->enabled, tm->pending);
|
| 279 |
|
| 280 | return 0;
|
| 281 | }
|
| 282 |
|
| 283 | static int nct3018y_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
| 284 | {
|
| 285 | struct i2c_client *client = to_i2c_client(dev);
|
| 286 | int err;
|
| 287 |
|
| 288 | dev_dbg(dev, "%s, sec=%d, min=%d hour=%d tm->enabled:%d\n",
|
| 289 | __func__, tm->time.tm_sec, tm->time.tm_min, tm->time.tm_hour,
|
| 290 | tm->enabled);
|
| 291 |
|
| 292 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_SCA, bin2bcd(tm->time.tm_sec));
|
| 293 | if (err < 0) {
|
| 294 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_SCA\n");
|
| 295 | return err;
|
| 296 | }
|
| 297 |
|
| 298 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_MNA, bin2bcd(tm->time.tm_min));
|
| 299 | if (err < 0) {
|
| 300 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_MNA\n");
|
| 301 | return err;
|
| 302 | }
|
| 303 |
|
| 304 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_HRA, bin2bcd(tm->time.tm_hour));
|
| 305 | if (err < 0) {
|
| 306 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_HRA\n");
|
| 307 | return err;
|
| 308 | }
|
| 309 |
|
| 310 | return nct3018y_set_alarm_mode(client, tm->enabled);
|
| 311 | }
|
| 312 |
|
| 313 | static int nct3018y_irq_enable(struct device *dev, unsigned int enabled)
|
| 314 | {
|
| 315 | dev_dbg(dev, "%s: alarm enable=%d\n", __func__, enabled);
|
| 316 |
|
| 317 | return nct3018y_set_alarm_mode(to_i2c_client(dev), enabled);
|
| 318 | }
|
| 319 |
|
| 320 | static int nct3018y_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
| 321 | {
|
| 322 | struct i2c_client *client = to_i2c_client(dev);
|
| 323 | int status, flags = 0;
|
| 324 |
|
| 325 | switch (cmd) {
|
| 326 | case RTC_VL_READ:
|
| 327 | status = i2c_smbus_read_byte_data(client, NCT3018Y_REG_ST);
|
| 328 | if (status < 0)
|
| 329 | return status;
|
| 330 |
|
| 331 | if (!(status & NCT3018Y_REG_BAT_MASK))
|
| 332 | flags |= RTC_VL_DATA_INVALID;
|
| 333 |
|
| 334 | return put_user(flags, (unsigned int __user *)arg);
|
| 335 |
|
| 336 | default:
|
| 337 | return -ENOIOCTLCMD;
|
| 338 | }
|
| 339 | }
|
| 340 |
|
| 341 | #ifdef CONFIG_COMMON_CLK
|
| 342 | |
| 343 | * Handling of the clkout
|
| 344 |
|
| 345 |
|
| 346 | #define clkout_hw_to_nct3018y(_hw) container_of(_hw, struct nct3018y, clkout_hw)
|
| 347 |
|
| 348 | static const int clkout_rates[] = {
|
| 349 | 32768,
|
| 350 | 1024,
|
| 351 | 32,
|
| 352 | 1,
|
| 353 | };
|
| 354 |
|
| 355 | static unsigned long nct3018y_clkout_recalc_rate(struct clk_hw *hw,
|
| 356 | unsigned long parent_rate)
|
| 357 | {
|
| 358 | struct nct3018y *nct3018y = clkout_hw_to_nct3018y(hw);
|
| 359 | struct i2c_client *client = nct3018y->client;
|
| 360 | int flags;
|
| 361 |
|
| 362 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CLKO);
|
| 363 | if (flags < 0)
|
| 364 | return 0;
|
| 365 |
|
| 366 | flags &= NCT3018Y_REG_CLKO_F_MASK;
|
| 367 | return clkout_rates[flags];
|
| 368 | }
|
| 369 |
|
| 370 | static int nct3018y_clkout_determine_rate(struct clk_hw *hw,
|
| 371 | struct clk_rate_request *req)
|
| 372 | {
|
| 373 | int i;
|
| 374 |
|
| 375 | for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
|
| 376 | if (clkout_rates[i] <= req->rate) {
|
| 377 | req->rate = clkout_rates[i];
|
| 378 |
|
| 379 | return 0;
|
| 380 | }
|
| 381 |
|
| 382 | req->rate = clkout_rates[0];
|
| 383 |
|
| 384 | return 0;
|
| 385 | }
|
| 386 |
|
| 387 | static int nct3018y_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
|
| 388 | unsigned long parent_rate)
|
| 389 | {
|
| 390 | struct nct3018y *nct3018y = clkout_hw_to_nct3018y(hw);
|
| 391 | struct i2c_client *client = nct3018y->client;
|
| 392 | int i, flags;
|
| 393 |
|
| 394 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CLKO);
|
| 395 | if (flags < 0)
|
| 396 | return flags;
|
| 397 |
|
| 398 | for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
|
| 399 | if (clkout_rates[i] == rate) {
|
| 400 | flags &= ~NCT3018Y_REG_CLKO_F_MASK;
|
| 401 | flags |= i;
|
| 402 | return i2c_smbus_write_byte_data(client, NCT3018Y_REG_CLKO, flags);
|
| 403 | }
|
| 404 |
|
| 405 | return -EINVAL;
|
| 406 | }
|
| 407 |
|
| 408 | static int nct3018y_clkout_control(struct clk_hw *hw, bool enable)
|
| 409 | {
|
| 410 | struct nct3018y *nct3018y = clkout_hw_to_nct3018y(hw);
|
| 411 | struct i2c_client *client = nct3018y->client;
|
| 412 | int flags;
|
| 413 |
|
| 414 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CLKO);
|
| 415 | if (flags < 0)
|
| 416 | return flags;
|
| 417 |
|
| 418 | if (enable)
|
| 419 | flags |= NCT3018Y_REG_CLKO_CKE;
|
| 420 | else
|
| 421 | flags &= ~NCT3018Y_REG_CLKO_CKE;
|
| 422 |
|
| 423 | return i2c_smbus_write_byte_data(client, NCT3018Y_REG_CLKO, flags);
|
| 424 | }
|
| 425 |
|
| 426 | static int nct3018y_clkout_prepare(struct clk_hw *hw)
|
| 427 | {
|
| 428 | return nct3018y_clkout_control(hw, 1);
|
| 429 | }
|
| 430 |
|
| 431 | static void nct3018y_clkout_unprepare(struct clk_hw *hw)
|
| 432 | {
|
| 433 | nct3018y_clkout_control(hw, 0);
|
| 434 | }
|
| 435 |
|
| 436 | static int nct3018y_clkout_is_prepared(struct clk_hw *hw)
|
| 437 | {
|
| 438 | struct nct3018y *nct3018y = clkout_hw_to_nct3018y(hw);
|
| 439 | struct i2c_client *client = nct3018y->client;
|
| 440 | int flags;
|
| 441 |
|
| 442 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CLKO);
|
| 443 | if (flags < 0)
|
| 444 | return flags;
|
| 445 |
|
| 446 | return flags & NCT3018Y_REG_CLKO_CKE;
|
| 447 | }
|
| 448 |
|
| 449 | static const struct clk_ops nct3018y_clkout_ops = {
|
| 450 | .prepare = nct3018y_clkout_prepare,
|
| 451 | .unprepare = nct3018y_clkout_unprepare,
|
| 452 | .is_prepared = nct3018y_clkout_is_prepared,
|
| 453 | .recalc_rate = nct3018y_clkout_recalc_rate,
|
| 454 | .determine_rate = nct3018y_clkout_determine_rate,
|
| 455 | .set_rate = nct3018y_clkout_set_rate,
|
| 456 | };
|
| 457 |
|
| 458 | static struct clk *nct3018y_clkout_register_clk(struct nct3018y *nct3018y)
|
| 459 | {
|
| 460 | struct i2c_client *client = nct3018y->client;
|
| 461 | struct device_node *node = client->dev.of_node;
|
| 462 | struct clk_init_data init = {};
|
| 463 | struct clk *clk;
|
| 464 |
|
| 465 | init.name = "nct3018y-clkout";
|
| 466 | init.ops = &nct3018y_clkout_ops;
|
| 467 | init.flags = 0;
|
| 468 | init.parent_names = NULL;
|
| 469 | init.num_parents = 0;
|
| 470 | nct3018y->clkout_hw.init = &init;
|
| 471 |
|
| 472 |
|
| 473 | of_property_read_string(node, "clock-output-names", &init.name);
|
| 474 |
|
| 475 |
|
| 476 | clk = devm_clk_register(&client->dev, &nct3018y->clkout_hw);
|
| 477 |
|
| 478 | if (!IS_ERR(clk))
|
| 479 | of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
| 480 |
|
| 481 | return clk;
|
| 482 | }
|
| 483 | #endif
|
| 484 |
|
| 485 | static const struct rtc_class_ops nct3018y_rtc_ops = {
|
| 486 | .read_time = nct3018y_rtc_read_time,
|
| 487 | .set_time = nct3018y_rtc_set_time,
|
| 488 | .read_alarm = nct3018y_rtc_read_alarm,
|
| 489 | .set_alarm = nct3018y_rtc_set_alarm,
|
| 490 | .alarm_irq_enable = nct3018y_irq_enable,
|
| 491 | .ioctl = nct3018y_ioctl,
|
| 492 | };
|
| 493 |
|
| 494 | static int nct3018y_probe(struct i2c_client *client)
|
| 495 | {
|
| 496 | struct nct3018y *nct3018y;
|
| 497 | int err, flags;
|
| 498 |
|
| 499 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
| 500 | I2C_FUNC_SMBUS_BYTE |
|
| 501 | I2C_FUNC_SMBUS_BLOCK_DATA))
|
| 502 | return -ENODEV;
|
| 503 |
|
| 504 | nct3018y = devm_kzalloc(&client->dev, sizeof(struct nct3018y),
|
| 505 | GFP_KERNEL);
|
| 506 | if (!nct3018y)
|
| 507 | return -ENOMEM;
|
| 508 |
|
| 509 | i2c_set_clientdata(client, nct3018y);
|
| 510 | nct3018y->client = client;
|
| 511 | device_set_wakeup_capable(&client->dev, 1);
|
| 512 |
|
| 513 | flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CTRL);
|
| 514 | if (flags < 0) {
|
| 515 | dev_dbg(&client->dev, "%s: read error\n", __func__);
|
| 516 | return flags;
|
| 517 | } else if (flags & NCT3018Y_BIT_TWO) {
|
| 518 | dev_dbg(&client->dev, "%s: NCT3018Y_BIT_TWO is set\n", __func__);
|
| 519 | }
|
| 520 |
|
| 521 | nct3018y->part_num = i2c_smbus_read_byte_data(client, NCT3018Y_REG_PART);
|
| 522 | if (nct3018y->part_num < 0) {
|
| 523 | dev_dbg(&client->dev, "Failed to read NCT3018Y_REG_PART.\n");
|
| 524 | return nct3018y->part_num;
|
| 525 | } else {
|
| 526 | nct3018y->part_num &= 0x03;
|
| 527 | if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y) {
|
| 528 | flags = NCT3018Y_BIT_HF;
|
| 529 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
|
| 530 | if (err < 0) {
|
| 531 | dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
|
| 532 | return err;
|
| 533 | }
|
| 534 | }
|
| 535 | }
|
| 536 |
|
| 537 | flags = 0;
|
| 538 | err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_ST, flags);
|
| 539 | if (err < 0) {
|
| 540 | dev_dbg(&client->dev, "%s: write error\n", __func__);
|
| 541 | return err;
|
| 542 | }
|
| 543 |
|
| 544 | nct3018y->rtc = devm_rtc_allocate_device(&client->dev);
|
| 545 | if (IS_ERR(nct3018y->rtc))
|
| 546 | return PTR_ERR(nct3018y->rtc);
|
| 547 |
|
| 548 | nct3018y->rtc->ops = &nct3018y_rtc_ops;
|
| 549 | nct3018y->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
| 550 | nct3018y->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
| 551 |
|
| 552 | if (client->irq > 0) {
|
| 553 | err = devm_request_threaded_irq(&client->dev, client->irq,
|
| 554 | NULL, nct3018y_irq,
|
| 555 | IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
|
| 556 | "nct3018y", client);
|
| 557 | if (err) {
|
| 558 | dev_dbg(&client->dev, "unable to request IRQ %d\n", client->irq);
|
| 559 | return err;
|
| 560 | }
|
| 561 | } else {
|
| 562 | clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, nct3018y->rtc->features);
|
| 563 | clear_bit(RTC_FEATURE_ALARM, nct3018y->rtc->features);
|
| 564 | }
|
| 565 |
|
| 566 | #ifdef CONFIG_COMMON_CLK
|
| 567 |
|
| 568 | nct3018y_clkout_register_clk(nct3018y);
|
| 569 | #endif
|
| 570 |
|
| 571 | return devm_rtc_register_device(nct3018y->rtc);
|
| 572 | }
|
| 573 |
|
| 574 | static const struct i2c_device_id nct3018y_id[] = {
|
| 575 | { .name = "nct3018y" },
|
| 576 | { }
|
| 577 | };
|
| 578 | MODULE_DEVICE_TABLE(i2c, nct3018y_id);
|
| 579 |
|
| 580 | static const struct of_device_id nct3018y_of_match[] = {
|
| 581 | { .compatible = "nuvoton,nct3018y" },
|
| 582 | {}
|
| 583 | };
|
| 584 | MODULE_DEVICE_TABLE(of, nct3018y_of_match);
|
| 585 |
|
| 586 | static struct i2c_driver nct3018y_driver = {
|
| 587 | .driver = {
|
| 588 | .name = "rtc-nct3018y",
|
| 589 | .of_match_table = nct3018y_of_match,
|
| 590 | },
|
| 591 | .probe = nct3018y_probe,
|
| 592 | .id_table = nct3018y_id,
|
| 593 | };
|
| 594 |
|
| 595 | module_i2c_driver(nct3018y_driver);
|
| 596 |
|
| 597 | MODULE_AUTHOR("Medad CChien <[email protected]>");
|
| 598 | MODULE_AUTHOR("Mia Lin <[email protected]>");
|
| 599 | MODULE_DESCRIPTION("Nuvoton NCT3018Y RTC driver");
|
| 600 | MODULE_LICENSE("GPL");
|