diff options
author | Jean Delvare <khali@linux-fr.org> | 2005-06-05 15:27:28 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-22 00:52:03 -0400 |
commit | 30d7394b1a3df0e7cc145a543846109babd4d53b (patch) | |
tree | e1118dba668df2123558a0a25913c4d4f460eae8 /drivers/i2c/chips | |
parent | a0ef14837a2298a4748e2a3e8e206f086dd3b21a (diff) |
[PATCH] I2C: lm90 uses new sysfs callbacks
I updated the lm90 hardware monitoring driver to take benefit of Yani
Ioannou's new sysfs callback capabilities.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/i2c/chips')
-rw-r--r-- | drivers/i2c/chips/lm90.c | 264 |
1 files changed, 147 insertions, 117 deletions
diff --git a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c index 42795b43c8b9..ebd99dfbf9c7 100644 --- a/drivers/i2c/chips/lm90.c +++ b/drivers/i2c/chips/lm90.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * lm90.c - Part of lm_sensors, Linux kernel modules for hardware | 2 | * lm90.c - Part of lm_sensors, Linux kernel modules for hardware |
3 | * monitoring | 3 | * monitoring |
4 | * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org> |
5 | * | 5 | * |
6 | * Based on the lm83 driver. The LM90 is a sensor chip made by National | 6 | * Based on the lm83 driver. The LM90 is a sensor chip made by National |
7 | * Semiconductor. It reports up to two temperatures (its own plus up to | 7 | * Semiconductor. It reports up to two temperatures (its own plus up to |
@@ -76,6 +76,7 @@ | |||
76 | #include <linux/jiffies.h> | 76 | #include <linux/jiffies.h> |
77 | #include <linux/i2c.h> | 77 | #include <linux/i2c.h> |
78 | #include <linux/i2c-sensor.h> | 78 | #include <linux/i2c-sensor.h> |
79 | #include <linux/i2c-sysfs.h> | ||
79 | 80 | ||
80 | /* | 81 | /* |
81 | * Addresses to scan | 82 | * Addresses to scan |
@@ -205,9 +206,14 @@ struct lm90_data { | |||
205 | int kind; | 206 | int kind; |
206 | 207 | ||
207 | /* registers values */ | 208 | /* registers values */ |
208 | s8 temp_input1, temp_low1, temp_high1; /* local */ | 209 | s8 temp8[5]; /* 0: local input |
209 | s16 temp_input2, temp_low2, temp_high2; /* remote, combined */ | 210 | 1: local low limit |
210 | s8 temp_crit1, temp_crit2; | 211 | 2: local high limit |
212 | 3: local critical limit | ||
213 | 4: remote critical limit */ | ||
214 | s16 temp11[3]; /* 0: remote input | ||
215 | 1: remote low limit | ||
216 | 2: remote high limit */ | ||
211 | u8 temp_hyst; | 217 | u8 temp_hyst; |
212 | u8 alarms; /* bitvector */ | 218 | u8 alarms; /* bitvector */ |
213 | }; | 219 | }; |
@@ -216,75 +222,88 @@ struct lm90_data { | |||
216 | * Sysfs stuff | 222 | * Sysfs stuff |
217 | */ | 223 | */ |
218 | 224 | ||
219 | #define show_temp(value, converter) \ | 225 | static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, |
220 | static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ | 226 | char *buf) |
221 | { \ | 227 | { |
222 | struct lm90_data *data = lm90_update_device(dev); \ | 228 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
223 | return sprintf(buf, "%d\n", converter(data->value)); \ | 229 | struct lm90_data *data = lm90_update_device(dev); |
230 | return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])); | ||
231 | } | ||
232 | |||
233 | static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, | ||
234 | const char *buf, size_t count) | ||
235 | { | ||
236 | static const u8 reg[4] = { | ||
237 | LM90_REG_W_LOCAL_LOW, | ||
238 | LM90_REG_W_LOCAL_HIGH, | ||
239 | LM90_REG_W_LOCAL_CRIT, | ||
240 | LM90_REG_W_REMOTE_CRIT, | ||
241 | }; | ||
242 | |||
243 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
244 | struct i2c_client *client = to_i2c_client(dev); | ||
245 | struct lm90_data *data = i2c_get_clientdata(client); | ||
246 | long val = simple_strtol(buf, NULL, 10); | ||
247 | int nr = attr->index; | ||
248 | |||
249 | down(&data->update_lock); | ||
250 | if (data->kind == adt7461) | ||
251 | data->temp8[nr] = TEMP1_TO_REG_ADT7461(val); | ||
252 | else | ||
253 | data->temp8[nr] = TEMP1_TO_REG(val); | ||
254 | i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]); | ||
255 | up(&data->update_lock); | ||
256 | return count; | ||
224 | } | 257 | } |
225 | show_temp(temp_input1, TEMP1_FROM_REG); | 258 | |
226 | show_temp(temp_input2, TEMP2_FROM_REG); | 259 | static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, |
227 | show_temp(temp_low1, TEMP1_FROM_REG); | 260 | char *buf) |
228 | show_temp(temp_low2, TEMP2_FROM_REG); | 261 | { |
229 | show_temp(temp_high1, TEMP1_FROM_REG); | 262 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
230 | show_temp(temp_high2, TEMP2_FROM_REG); | 263 | struct lm90_data *data = lm90_update_device(dev); |
231 | show_temp(temp_crit1, TEMP1_FROM_REG); | 264 | return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index])); |
232 | show_temp(temp_crit2, TEMP1_FROM_REG); | ||
233 | |||
234 | #define set_temp1(value, reg) \ | ||
235 | static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ | ||
236 | size_t count) \ | ||
237 | { \ | ||
238 | struct i2c_client *client = to_i2c_client(dev); \ | ||
239 | struct lm90_data *data = i2c_get_clientdata(client); \ | ||
240 | long val = simple_strtol(buf, NULL, 10); \ | ||
241 | \ | ||
242 | down(&data->update_lock); \ | ||
243 | if (data->kind == adt7461) \ | ||
244 | data->value = TEMP1_TO_REG_ADT7461(val); \ | ||
245 | else \ | ||
246 | data->value = TEMP1_TO_REG(val); \ | ||
247 | i2c_smbus_write_byte_data(client, reg, data->value); \ | ||
248 | up(&data->update_lock); \ | ||
249 | return count; \ | ||
250 | } | 265 | } |
251 | #define set_temp2(value, regh, regl) \ | 266 | |
252 | static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ | 267 | static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, |
253 | size_t count) \ | 268 | const char *buf, size_t count) |
254 | { \ | 269 | { |
255 | struct i2c_client *client = to_i2c_client(dev); \ | 270 | static const u8 reg[4] = { |
256 | struct lm90_data *data = i2c_get_clientdata(client); \ | 271 | LM90_REG_W_REMOTE_LOWH, |
257 | long val = simple_strtol(buf, NULL, 10); \ | 272 | LM90_REG_W_REMOTE_LOWL, |
258 | \ | 273 | LM90_REG_W_REMOTE_HIGHH, |
259 | down(&data->update_lock); \ | 274 | LM90_REG_W_REMOTE_HIGHL, |
260 | if (data->kind == adt7461) \ | 275 | }; |
261 | data->value = TEMP2_TO_REG_ADT7461(val); \ | 276 | |
262 | else \ | 277 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
263 | data->value = TEMP2_TO_REG(val); \ | 278 | struct i2c_client *client = to_i2c_client(dev); |
264 | i2c_smbus_write_byte_data(client, regh, data->value >> 8); \ | 279 | struct lm90_data *data = i2c_get_clientdata(client); |
265 | i2c_smbus_write_byte_data(client, regl, data->value & 0xff); \ | 280 | long val = simple_strtol(buf, NULL, 10); |
266 | up(&data->update_lock); \ | 281 | int nr = attr->index; |
267 | return count; \ | 282 | |
283 | down(&data->update_lock); | ||
284 | if (data->kind == adt7461) | ||
285 | data->temp11[nr] = TEMP2_TO_REG_ADT7461(val); | ||
286 | else | ||
287 | data->temp11[nr] = TEMP2_TO_REG(val); | ||
288 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], | ||
289 | data->temp11[nr] >> 8); | ||
290 | i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], | ||
291 | data->temp11[nr] & 0xff); | ||
292 | up(&data->update_lock); | ||
293 | return count; | ||
268 | } | 294 | } |
269 | set_temp1(temp_low1, LM90_REG_W_LOCAL_LOW); | 295 | |
270 | set_temp2(temp_low2, LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL); | 296 | static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr, |
271 | set_temp1(temp_high1, LM90_REG_W_LOCAL_HIGH); | 297 | char *buf) |
272 | set_temp2(temp_high2, LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL); | 298 | { |
273 | set_temp1(temp_crit1, LM90_REG_W_LOCAL_CRIT); | 299 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
274 | set_temp1(temp_crit2, LM90_REG_W_REMOTE_CRIT); | 300 | struct lm90_data *data = lm90_update_device(dev); |
275 | 301 | return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]) | |
276 | #define show_temp_hyst(value, basereg) \ | 302 | - TEMP1_FROM_REG(data->temp_hyst)); |
277 | static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ | ||
278 | { \ | ||
279 | struct lm90_data *data = lm90_update_device(dev); \ | ||
280 | return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->basereg) \ | ||
281 | - TEMP1_FROM_REG(data->temp_hyst)); \ | ||
282 | } | 303 | } |
283 | show_temp_hyst(temp_hyst1, temp_crit1); | ||
284 | show_temp_hyst(temp_hyst2, temp_crit2); | ||
285 | 304 | ||
286 | static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, const char *buf, | 305 | static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, |
287 | size_t count) | 306 | const char *buf, size_t count) |
288 | { | 307 | { |
289 | struct i2c_client *client = to_i2c_client(dev); | 308 | struct i2c_client *client = to_i2c_client(dev); |
290 | struct lm90_data *data = i2c_get_clientdata(client); | 309 | struct lm90_data *data = i2c_get_clientdata(client); |
@@ -292,36 +311,37 @@ static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, | |||
292 | long hyst; | 311 | long hyst; |
293 | 312 | ||
294 | down(&data->update_lock); | 313 | down(&data->update_lock); |
295 | hyst = TEMP1_FROM_REG(data->temp_crit1) - val; | 314 | hyst = TEMP1_FROM_REG(data->temp8[3]) - val; |
296 | i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, | 315 | i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, |
297 | HYST_TO_REG(hyst)); | 316 | HYST_TO_REG(hyst)); |
298 | up(&data->update_lock); | 317 | up(&data->update_lock); |
299 | return count; | 318 | return count; |
300 | } | 319 | } |
301 | 320 | ||
302 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) | 321 | static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, |
322 | char *buf) | ||
303 | { | 323 | { |
304 | struct lm90_data *data = lm90_update_device(dev); | 324 | struct lm90_data *data = lm90_update_device(dev); |
305 | return sprintf(buf, "%d\n", data->alarms); | 325 | return sprintf(buf, "%d\n", data->alarms); |
306 | } | 326 | } |
307 | 327 | ||
308 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); | 328 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); |
309 | static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); | 329 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); |
310 | static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_low1, | 330 | static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, |
311 | set_temp_low1); | 331 | set_temp8, 1); |
312 | static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2, | 332 | static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, |
313 | set_temp_low2); | 333 | set_temp11, 1); |
314 | static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1, | 334 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, |
315 | set_temp_high1); | 335 | set_temp8, 2); |
316 | static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2, | 336 | static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, |
317 | set_temp_high2); | 337 | set_temp11, 2); |
318 | static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit1, | 338 | static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, |
319 | set_temp_crit1); | 339 | set_temp8, 3); |
320 | static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2, | 340 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, |
321 | set_temp_crit2); | 341 | set_temp8, 4); |
322 | static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst1, | 342 | static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, |
323 | set_temp_hyst1); | 343 | set_temphyst, 3); |
324 | static DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_hyst2, NULL); | 344 | static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); |
325 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 345 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
326 | 346 | ||
327 | /* | 347 | /* |
@@ -480,16 +500,26 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) | |||
480 | lm90_init_client(new_client); | 500 | lm90_init_client(new_client); |
481 | 501 | ||
482 | /* Register sysfs hooks */ | 502 | /* Register sysfs hooks */ |
483 | device_create_file(&new_client->dev, &dev_attr_temp1_input); | 503 | device_create_file(&new_client->dev, |
484 | device_create_file(&new_client->dev, &dev_attr_temp2_input); | 504 | &sensor_dev_attr_temp1_input.dev_attr); |
485 | device_create_file(&new_client->dev, &dev_attr_temp1_min); | 505 | device_create_file(&new_client->dev, |
486 | device_create_file(&new_client->dev, &dev_attr_temp2_min); | 506 | &sensor_dev_attr_temp2_input.dev_attr); |
487 | device_create_file(&new_client->dev, &dev_attr_temp1_max); | 507 | device_create_file(&new_client->dev, |
488 | device_create_file(&new_client->dev, &dev_attr_temp2_max); | 508 | &sensor_dev_attr_temp1_min.dev_attr); |
489 | device_create_file(&new_client->dev, &dev_attr_temp1_crit); | 509 | device_create_file(&new_client->dev, |
490 | device_create_file(&new_client->dev, &dev_attr_temp2_crit); | 510 | &sensor_dev_attr_temp2_min.dev_attr); |
491 | device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); | 511 | device_create_file(&new_client->dev, |
492 | device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); | 512 | &sensor_dev_attr_temp1_max.dev_attr); |
513 | device_create_file(&new_client->dev, | ||
514 | &sensor_dev_attr_temp2_max.dev_attr); | ||
515 | device_create_file(&new_client->dev, | ||
516 | &sensor_dev_attr_temp1_crit.dev_attr); | ||
517 | device_create_file(&new_client->dev, | ||
518 | &sensor_dev_attr_temp2_crit.dev_attr); | ||
519 | device_create_file(&new_client->dev, | ||
520 | &sensor_dev_attr_temp1_crit_hyst.dev_attr); | ||
521 | device_create_file(&new_client->dev, | ||
522 | &sensor_dev_attr_temp2_crit_hyst.dev_attr); | ||
493 | device_create_file(&new_client->dev, &dev_attr_alarms); | 523 | device_create_file(&new_client->dev, &dev_attr_alarms); |
494 | 524 | ||
495 | return 0; | 525 | return 0; |
@@ -540,16 +570,16 @@ static struct lm90_data *lm90_update_device(struct device *dev) | |||
540 | u8 oldh, newh; | 570 | u8 oldh, newh; |
541 | 571 | ||
542 | dev_dbg(&client->dev, "Updating lm90 data.\n"); | 572 | dev_dbg(&client->dev, "Updating lm90 data.\n"); |
543 | data->temp_input1 = i2c_smbus_read_byte_data(client, | 573 | data->temp8[0] = i2c_smbus_read_byte_data(client, |
544 | LM90_REG_R_LOCAL_TEMP); | 574 | LM90_REG_R_LOCAL_TEMP); |
545 | data->temp_high1 = i2c_smbus_read_byte_data(client, | 575 | data->temp8[1] = i2c_smbus_read_byte_data(client, |
546 | LM90_REG_R_LOCAL_HIGH); | 576 | LM90_REG_R_LOCAL_LOW); |
547 | data->temp_low1 = i2c_smbus_read_byte_data(client, | 577 | data->temp8[2] = i2c_smbus_read_byte_data(client, |
548 | LM90_REG_R_LOCAL_LOW); | 578 | LM90_REG_R_LOCAL_HIGH); |
549 | data->temp_crit1 = i2c_smbus_read_byte_data(client, | 579 | data->temp8[3] = i2c_smbus_read_byte_data(client, |
550 | LM90_REG_R_LOCAL_CRIT); | 580 | LM90_REG_R_LOCAL_CRIT); |
551 | data->temp_crit2 = i2c_smbus_read_byte_data(client, | 581 | data->temp8[4] = i2c_smbus_read_byte_data(client, |
552 | LM90_REG_R_REMOTE_CRIT); | 582 | LM90_REG_R_REMOTE_CRIT); |
553 | data->temp_hyst = i2c_smbus_read_byte_data(client, | 583 | data->temp_hyst = i2c_smbus_read_byte_data(client, |
554 | LM90_REG_R_TCRIT_HYST); | 584 | LM90_REG_R_TCRIT_HYST); |
555 | 585 | ||
@@ -569,13 +599,13 @@ static struct lm90_data *lm90_update_device(struct device *dev) | |||
569 | */ | 599 | */ |
570 | oldh = i2c_smbus_read_byte_data(client, | 600 | oldh = i2c_smbus_read_byte_data(client, |
571 | LM90_REG_R_REMOTE_TEMPH); | 601 | LM90_REG_R_REMOTE_TEMPH); |
572 | data->temp_input2 = i2c_smbus_read_byte_data(client, | 602 | data->temp11[0] = i2c_smbus_read_byte_data(client, |
573 | LM90_REG_R_REMOTE_TEMPL); | 603 | LM90_REG_R_REMOTE_TEMPL); |
574 | newh = i2c_smbus_read_byte_data(client, | 604 | newh = i2c_smbus_read_byte_data(client, |
575 | LM90_REG_R_REMOTE_TEMPH); | 605 | LM90_REG_R_REMOTE_TEMPH); |
576 | if (newh != oldh) { | 606 | if (newh != oldh) { |
577 | data->temp_input2 = i2c_smbus_read_byte_data(client, | 607 | data->temp11[0] = i2c_smbus_read_byte_data(client, |
578 | LM90_REG_R_REMOTE_TEMPL); | 608 | LM90_REG_R_REMOTE_TEMPL); |
579 | #ifdef DEBUG | 609 | #ifdef DEBUG |
580 | oldh = i2c_smbus_read_byte_data(client, | 610 | oldh = i2c_smbus_read_byte_data(client, |
581 | LM90_REG_R_REMOTE_TEMPH); | 611 | LM90_REG_R_REMOTE_TEMPH); |
@@ -585,16 +615,16 @@ static struct lm90_data *lm90_update_device(struct device *dev) | |||
585 | "wrong.\n"); | 615 | "wrong.\n"); |
586 | #endif | 616 | #endif |
587 | } | 617 | } |
588 | data->temp_input2 |= (newh << 8); | 618 | data->temp11[0] |= (newh << 8); |
589 | 619 | ||
590 | data->temp_high2 = (i2c_smbus_read_byte_data(client, | 620 | data->temp11[1] = (i2c_smbus_read_byte_data(client, |
621 | LM90_REG_R_REMOTE_LOWH) << 8) + | ||
622 | i2c_smbus_read_byte_data(client, | ||
623 | LM90_REG_R_REMOTE_LOWL); | ||
624 | data->temp11[2] = (i2c_smbus_read_byte_data(client, | ||
591 | LM90_REG_R_REMOTE_HIGHH) << 8) + | 625 | LM90_REG_R_REMOTE_HIGHH) << 8) + |
592 | i2c_smbus_read_byte_data(client, | 626 | i2c_smbus_read_byte_data(client, |
593 | LM90_REG_R_REMOTE_HIGHL); | 627 | LM90_REG_R_REMOTE_HIGHL); |
594 | data->temp_low2 = (i2c_smbus_read_byte_data(client, | ||
595 | LM90_REG_R_REMOTE_LOWH) << 8) + | ||
596 | i2c_smbus_read_byte_data(client, | ||
597 | LM90_REG_R_REMOTE_LOWL); | ||
598 | data->alarms = i2c_smbus_read_byte_data(client, | 628 | data->alarms = i2c_smbus_read_byte_data(client, |
599 | LM90_REG_R_STATUS); | 629 | LM90_REG_R_STATUS); |
600 | 630 | ||