Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

at86rf230: add support for external xtal trim

This patch adds support for setting the xtal trim register. Some at86rf2xx
transceiver boards needs fine tuning the xtal capacitor.

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Alexander Aring and committed by
Marcel Holtmann
ccdaeb2b aaa1c4d2

+54 -4
+3
Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt
··· 11 11 Optional properties: 12 12 - reset-gpio: GPIO spec for the rstn pin 13 13 - sleep-gpio: GPIO spec for the slp_tr pin 14 + - xtal-trim: u8 value for fine tuning the internal capacitance 15 + arrays of xtal pins: 0 = +0 pF, 0xf = +4.5 pF 14 16 15 17 Example: 16 18 ··· 22 20 reg = <0>; 23 21 interrupts = <19 1>; 24 22 interrupt-parent = <&gpio3>; 23 + xtal-trim = /bits/ 8 <0x06>; 25 24 };
+50 -4
drivers/net/ieee802154/at86rf230.c
··· 1315 1315 .get_desense_steps = at86rf212_get_desens_steps 1316 1316 }; 1317 1317 1318 - static int at86rf230_hw_init(struct at86rf230_local *lp) 1318 + static int at86rf230_hw_init(struct at86rf230_local *lp, u8 xtal_trim) 1319 1319 { 1320 1320 int rc, irq_type, irq_pol = IRQ_ACTIVE_HIGH; 1321 1321 unsigned int dvdd; ··· 1362 1362 usleep_range(lp->data->t_sleep_cycle, 1363 1363 lp->data->t_sleep_cycle + 100); 1364 1364 1365 + /* xtal_trim value is calculated by: 1366 + * CL = 0.5 * (CX + CTRIM + CPAR) 1367 + * 1368 + * whereas: 1369 + * CL = capacitor of used crystal 1370 + * CX = connected capacitors at xtal pins 1371 + * CPAR = in all at86rf2xx datasheets this is a constant value 3 pF, 1372 + * but this is different on each board setup. You need to fine 1373 + * tuning this value via CTRIM. 1374 + * CTRIM = variable capacitor setting. Resolution is 0.3 pF range is 1375 + * 0 pF upto 4.5 pF. 1376 + * 1377 + * Examples: 1378 + * atben transceiver: 1379 + * 1380 + * CL = 8 pF 1381 + * CX = 12 pF 1382 + * CPAR = 3 pF (We assume the magic constant from datasheet) 1383 + * CTRIM = 0.9 pF 1384 + * 1385 + * (12+0.9+3)/2 = 7.95 which is nearly at 8 pF 1386 + * 1387 + * xtal_trim = 0x3 1388 + * 1389 + * openlabs transceiver: 1390 + * 1391 + * CL = 16 pF 1392 + * CX = 22 pF 1393 + * CPAR = 3 pF (We assume the magic constant from datasheet) 1394 + * CTRIM = 4.5 pF 1395 + * 1396 + * (22+4.5+3)/2 = 14.75 which is the nearest value to 16 pF 1397 + * 1398 + * xtal_trim = 0xf 1399 + */ 1400 + rc = at86rf230_write_subreg(lp, SR_XTAL_TRIM, xtal_trim); 1401 + if (rc) 1402 + return rc; 1403 + 1365 1404 rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &dvdd); 1366 1405 if (rc) 1367 1406 return rc; ··· 1417 1378 } 1418 1379 1419 1380 static int 1420 - at86rf230_get_pdata(struct spi_device *spi, int *rstn, int *slp_tr) 1381 + at86rf230_get_pdata(struct spi_device *spi, int *rstn, int *slp_tr, 1382 + u8 *xtal_trim) 1421 1383 { 1422 1384 struct at86rf230_platform_data *pdata = spi->dev.platform_data; 1385 + int ret; 1423 1386 1424 1387 if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node) { 1425 1388 if (!pdata) ··· 1429 1388 1430 1389 *rstn = pdata->rstn; 1431 1390 *slp_tr = pdata->slp_tr; 1391 + *xtal_trim = pdata->xtal_trim; 1432 1392 return 0; 1433 1393 } 1434 1394 1435 1395 *rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0); 1436 1396 *slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0); 1397 + ret = of_property_read_u8(spi->dev.of_node, "xtal-trim", xtal_trim); 1398 + if (ret < 0 && ret != -EINVAL) 1399 + return ret; 1437 1400 1438 1401 return 0; 1439 1402 } ··· 1550 1505 struct at86rf230_local *lp; 1551 1506 unsigned int status; 1552 1507 int rc, irq_type, rstn, slp_tr; 1508 + u8 xtal_trim; 1553 1509 1554 1510 if (!spi->irq) { 1555 1511 dev_err(&spi->dev, "no IRQ specified\n"); 1556 1512 return -EINVAL; 1557 1513 } 1558 1514 1559 - rc = at86rf230_get_pdata(spi, &rstn, &slp_tr); 1515 + rc = at86rf230_get_pdata(spi, &rstn, &slp_tr, &xtal_trim); 1560 1516 if (rc < 0) { 1561 1517 dev_err(&spi->dev, "failed to parse platform_data: %d\n", rc); 1562 1518 return rc; ··· 1616 1570 1617 1571 spi_set_drvdata(spi, lp); 1618 1572 1619 - rc = at86rf230_hw_init(lp); 1573 + rc = at86rf230_hw_init(lp, xtal_trim); 1620 1574 if (rc) 1621 1575 goto free_dev; 1622 1576
+1
include/linux/spi/at86rf230.h
··· 22 22 int rstn; 23 23 int slp_tr; 24 24 int dig2; 25 + u8 xtal_trim; 25 26 }; 26 27 27 28 #endif