138774Snsouch/*-
238774Snsouch * Copyright (c) 1998 Nicolas Souchu
338774Snsouch * All rights reserved.
438774Snsouch *
538774Snsouch * Redistribution and use in source and binary forms, with or without
638774Snsouch * modification, are permitted provided that the following conditions
738774Snsouch * are met:
838774Snsouch * 1. Redistributions of source code must retain the above copyright
938774Snsouch *    notice, this list of conditions and the following disclaimer.
1038774Snsouch * 2. Redistributions in binary form must reproduce the above copyright
1138774Snsouch *    notice, this list of conditions and the following disclaimer in the
1238774Snsouch *    documentation and/or other materials provided with the distribution.
1338774Snsouch *
1438774Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538774Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638774Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738774Snsouch * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838774Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938774Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038774Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138774Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238774Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338774Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438774Snsouch * SUCH DAMAGE.
2538774Snsouch */
26119418Sobrien
27119418Sobrien#include <sys/cdefs.h>
28119418Sobrien__FBSDID("$FreeBSD: stable/11/sys/dev/iicbus/iiconf.c 350031 2019-07-16 15:02:28Z avg $");
29119418Sobrien
3038774Snsouch#include <sys/param.h>
3138774Snsouch#include <sys/systm.h>
32181304Sjhb#include <sys/lock.h>
33167855Simp#include <sys/malloc.h>
3438774Snsouch#include <sys/module.h>
35181304Sjhb#include <sys/mutex.h>
3638774Snsouch#include <sys/bus.h>
3738774Snsouch
3838774Snsouch#include <dev/iicbus/iiconf.h>
3938774Snsouch#include <dev/iicbus/iicbus.h>
4038774Snsouch#include "iicbus_if.h"
4138774Snsouch
4238774Snsouch/*
43289095Sian * Translate IIC_Exxxxx status values to vaguely-equivelent errno values.
44289095Sian */
45289095Sianint
46289095Sianiic2errno(int iic_status)
47289095Sian{
48289095Sian	switch (iic_status) {
49289095Sian	case IIC_NOERR:         return (0);
50289095Sian	case IIC_EBUSERR:       return (EALREADY);
51289095Sian	case IIC_ENOACK:        return (EIO);
52289095Sian	case IIC_ETIMEOUT:      return (ETIMEDOUT);
53289095Sian	case IIC_EBUSBSY:       return (EWOULDBLOCK);
54289095Sian	case IIC_ESTATUS:       return (EPROTO);
55289095Sian	case IIC_EUNDERFLOW:    return (EIO);
56289095Sian	case IIC_EOVERFLOW:     return (EOVERFLOW);
57289095Sian	case IIC_ENOTSUPP:      return (EOPNOTSUPP);
58289095Sian	case IIC_ENOADDR:       return (EADDRNOTAVAIL);
59289095Sian	case IIC_ERESOURCE:     return (ENOMEM);
60289095Sian	default:                return (EIO);
61289095Sian	}
62289095Sian}
63289095Sian
64289095Sian/*
6538774Snsouch * iicbus_intr()
6638774Snsouch */
6738774Snsouchvoid
6838774Snsouchiicbus_intr(device_t bus, int event, char *buf)
6938774Snsouch{
7038774Snsouch	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
7138774Snsouch
7238774Snsouch	/* call owner's intr routine */
7338774Snsouch	if (sc->owner)
7438774Snsouch		IICBUS_INTR(sc->owner, event, buf);
7538774Snsouch
7638774Snsouch	return;
7738774Snsouch}
7838774Snsouch
7940782Snsouchstatic int
8040782Snsouchiicbus_poll(struct iicbus_softc *sc, int how)
8140782Snsouch{
8240782Snsouch	int error;
8340782Snsouch
84181304Sjhb	IICBUS_ASSERT_LOCKED(sc);
85331497Sian	switch (how & IIC_INTRWAIT) {
86181304Sjhb	case IIC_WAIT | IIC_INTR:
87181304Sjhb		error = mtx_sleep(sc, &sc->lock, IICPRI|PCATCH, "iicreq", 0);
8840782Snsouch		break;
8940782Snsouch
90181304Sjhb	case IIC_WAIT | IIC_NOINTR:
91181304Sjhb		error = mtx_sleep(sc, &sc->lock, IICPRI, "iicreq", 0);
9240782Snsouch		break;
9340782Snsouch
9440782Snsouch	default:
95289098Sian		return (IIC_EBUSBSY);
9640782Snsouch	}
9740782Snsouch
9840782Snsouch	return (error);
9940782Snsouch}
10040782Snsouch
10138774Snsouch/*
10238774Snsouch * iicbus_request_bus()
10338774Snsouch *
10438774Snsouch * Allocate the device to perform transfers.
10538774Snsouch *
10638774Snsouch * how	: IIC_WAIT or IIC_DONTWAIT
10738774Snsouch */
10838774Snsouchint
10938774Snsouchiicbus_request_bus(device_t bus, device_t dev, int how)
11038774Snsouch{
11138774Snsouch	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
112181304Sjhb	int error = 0;
11338774Snsouch
114181304Sjhb	IICBUS_LOCK(sc);
11540782Snsouch
116331497Sian	for (;;) {
117331497Sian		if (sc->owner == NULL)
118331497Sian			break;
119331497Sian		if ((how & IIC_RECURSIVE) && sc->owner == dev)
120331497Sian			break;
121331497Sian		if ((error = iicbus_poll(sc, how)) != 0)
122331497Sian			break;
123331497Sian	}
12438774Snsouch
125281828Sjah	if (error == 0) {
126323446Sian		++sc->owncount;
127323446Sian		if (sc->owner == NULL) {
128323446Sian			sc->owner = dev;
129323446Sian			/*
130323446Sian			 * Drop the lock around the call to the bus driver, it
131323446Sian			 * should be allowed to sleep in the IIC_WAIT case.
132323446Sian			 * Drivers might also need to grab locks that would
133323446Sian			 * cause a LOR if our lock is held.
134323446Sian			 */
135323446Sian			IICBUS_UNLOCK(sc);
136323446Sian			/* Ask the underlying layers if the request is ok */
137323446Sian			error = IICBUS_CALLBACK(device_get_parent(bus),
138323446Sian			    IIC_REQUEST_BUS, (caddr_t)&how);
139323446Sian			IICBUS_LOCK(sc);
140323446Sian
141323446Sian			if (error != 0) {
142323446Sian				sc->owner = NULL;
143323446Sian				sc->owncount = 0;
144323446Sian				wakeup_one(sc);
145323446Sian			}
14638774Snsouch		}
147281828Sjah	}
14843976Snsouch
149181304Sjhb	IICBUS_UNLOCK(sc);
15038774Snsouch
15138774Snsouch	return (error);
15238774Snsouch}
15338774Snsouch
15438774Snsouch/*
15538774Snsouch * iicbus_release_bus()
15638774Snsouch *
15738774Snsouch * Release the device allocated with iicbus_request_dev()
15838774Snsouch */
15938774Snsouchint
16038774Snsouchiicbus_release_bus(device_t bus, device_t dev)
16138774Snsouch{
16238774Snsouch	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
16338774Snsouch
164181304Sjhb	IICBUS_LOCK(sc);
165181304Sjhb
16638774Snsouch	if (sc->owner != dev) {
167181304Sjhb		IICBUS_UNLOCK(sc);
168289098Sian		return (IIC_EBUSBSY);
16938774Snsouch	}
17038774Snsouch
171323446Sian	if (--sc->owncount == 0) {
172323446Sian		/* Drop the lock while informing the low-level driver. */
173323446Sian		IICBUS_UNLOCK(sc);
174323446Sian		IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);
175281828Sjah		IICBUS_LOCK(sc);
176281828Sjah		sc->owner = NULL;
177281828Sjah		wakeup_one(sc);
178281828Sjah	}
179323446Sian	IICBUS_UNLOCK(sc);
180323446Sian	return (0);
18138774Snsouch}
18238774Snsouch
18338774Snsouch/*
18442442Snsouch * iicbus_started()
18542442Snsouch *
18642442Snsouch * Test if the iicbus is started by the controller
18742442Snsouch */
18842442Snsouchint
18942442Snsouchiicbus_started(device_t bus)
19042442Snsouch{
19142442Snsouch	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
19242442Snsouch
19342442Snsouch	return (sc->started);
19442442Snsouch}
19542442Snsouch
19642442Snsouch/*
19742442Snsouch * iicbus_start()
19842442Snsouch *
19942442Snsouch * Send start condition to the slave addressed by 'slave'
20042442Snsouch */
20142442Snsouchint
20242442Snsouchiicbus_start(device_t bus, u_char slave, int timeout)
20342442Snsouch{
20442442Snsouch	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
20542442Snsouch	int error = 0;
20642442Snsouch
20742442Snsouch	if (sc->started)
208289097Sian		return (IIC_ESTATUS); /* protocol error, bus already started */
20942442Snsouch
21042442Snsouch	if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout)))
21142442Snsouch		sc->started = slave;
21242442Snsouch	else
21342442Snsouch		sc->started = 0;
21442442Snsouch
21542442Snsouch	return (error);
21642442Snsouch}
21742442Snsouch
21842442Snsouch/*
21943347Sroger * iicbus_repeated_start()
22043347Sroger *
22143347Sroger * Send start condition to the slave addressed by 'slave'
22243347Sroger */
22343347Srogerint
22443347Srogeriicbus_repeated_start(device_t bus, u_char slave, int timeout)
22543347Sroger{
22643347Sroger	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
22743347Sroger	int error = 0;
22843347Sroger
22943347Sroger	if (!sc->started)
230289097Sian		return (IIC_ESTATUS); /* protocol error, bus not started */
23143347Sroger
23243714Sroger	if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout)))
23343347Sroger		sc->started = slave;
23443347Sroger	else
23543347Sroger		sc->started = 0;
23643347Sroger
23743347Sroger	return (error);
23843347Sroger}
23943347Sroger
24043347Sroger/*
24142442Snsouch * iicbus_stop()
24242442Snsouch *
24342442Snsouch * Send stop condition to the bus
24442442Snsouch */
24542442Snsouchint
24642442Snsouchiicbus_stop(device_t bus)
24742442Snsouch{
24842442Snsouch	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
24942442Snsouch	int error = 0;
25042442Snsouch
25142442Snsouch	if (!sc->started)
252289097Sian		return (IIC_ESTATUS); /* protocol error, bus not started */
25342442Snsouch
25442442Snsouch	error = IICBUS_STOP(device_get_parent(bus));
25542442Snsouch
25642442Snsouch	/* refuse any further access */
25742442Snsouch	sc->started = 0;
25842442Snsouch
25942442Snsouch	return (error);
26042442Snsouch}
26142442Snsouch
26242442Snsouch/*
26342442Snsouch * iicbus_write()
26442442Snsouch *
26542442Snsouch * Write a block of data to the slave previously started by
26642442Snsouch * iicbus_start() call
26742442Snsouch */
26842442Snsouchint
269164901Simpiicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout)
27042442Snsouch{
27142442Snsouch	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
27242442Snsouch
273228257Sadrian	/* a slave must have been started for writing */
274228257Sadrian	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0))
275289097Sian		return (IIC_ESTATUS);
27642442Snsouch
27742442Snsouch	return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout));
27842442Snsouch}
27942442Snsouch
28042442Snsouch/*
28142442Snsouch * iicbus_read()
28242442Snsouch *
28342442Snsouch * Read a block of data from the slave previously started by
28442442Snsouch * iicbus_read() call
28542442Snsouch */
28642442Snsouchint
28742442Snsouchiicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay)
28842442Snsouch{
28942442Snsouch	struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
29042442Snsouch
291228257Sadrian	/* a slave must have been started for reading */
292228257Sadrian	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0))
293289097Sian		return (IIC_ESTATUS);
29442442Snsouch
29542442Snsouch	return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay));
29642442Snsouch}
29742442Snsouch
29842442Snsouch/*
29943347Sroger * iicbus_write_byte()
30043347Sroger *
30143347Sroger * Write a byte to the slave previously started by iicbus_start() call
30243347Sroger */
30343347Srogerint
30443347Srogeriicbus_write_byte(device_t bus, char byte, int timeout)
30543347Sroger{
306289097Sian	struct iicbus_softc *sc = device_get_softc(bus);
30743347Sroger	char data = byte;
30843347Sroger	int sent;
30943347Sroger
310289097Sian	/* a slave must have been started for writing */
311289097Sian	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0))
312289097Sian		return (IIC_ESTATUS);
313289097Sian
31443347Sroger	return (iicbus_write(bus, &data, 1, &sent, timeout));
31543347Sroger}
31643347Sroger
31743347Sroger/*
31843347Sroger * iicbus_read_byte()
31943347Sroger *
32043347Sroger * Read a byte from the slave previously started by iicbus_start() call
32143347Sroger */
32243347Srogerint
32343347Srogeriicbus_read_byte(device_t bus, char *byte, int timeout)
32443347Sroger{
325289097Sian	struct iicbus_softc *sc = device_get_softc(bus);
32643347Sroger	int read;
32743347Sroger
328289097Sian	/* a slave must have been started for reading */
329289097Sian	if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0))
330289097Sian		return (IIC_ESTATUS);
331289097Sian
33243347Sroger	return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout));
33343347Sroger}
33443347Sroger
33543347Sroger/*
33638774Snsouch * iicbus_block_write()
33738774Snsouch *
33838774Snsouch * Write a block of data to slave ; start/stop protocol managed
33938774Snsouch */
34038774Snsouchint
34138774Snsouchiicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent)
34238774Snsouch{
34338774Snsouch	u_char addr = slave & ~LSB;
34438774Snsouch	int error;
34538774Snsouch
34640782Snsouch	if ((error = iicbus_start(bus, addr, 0)))
34738774Snsouch		return (error);
34838774Snsouch
34940782Snsouch	error = iicbus_write(bus, buf, len, sent, 0);
35038774Snsouch
35138774Snsouch	iicbus_stop(bus);
35238774Snsouch
35338774Snsouch	return (error);
35438774Snsouch}
35538774Snsouch
35638774Snsouch/*
35738774Snsouch * iicbus_block_read()
35838774Snsouch *
35938774Snsouch * Read a block of data from slave ; start/stop protocol managed
36038774Snsouch */
36138774Snsouchint
36238774Snsouchiicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read)
36338774Snsouch{
36438774Snsouch	u_char addr = slave | LSB;
36538774Snsouch	int error;
36638774Snsouch
36740782Snsouch	if ((error = iicbus_start(bus, addr, 0)))
36838774Snsouch		return (error);
36938774Snsouch
37040782Snsouch	error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0);
37138774Snsouch
37240782Snsouch	iicbus_stop(bus);
37338774Snsouch
37438774Snsouch	return (error);
37538774Snsouch}
376160372Simp
377160372Simp/*
378181304Sjhb * iicbus_transfer()
379160372Simp *
380160372Simp * Do an aribtrary number of transfers on the iicbus.  We pass these
381160372Simp * raw requests to the bridge driver.  If the bridge driver supports
382160372Simp * them directly, then it manages all the details.  If not, it can use
383160372Simp * the helper function iicbus_transfer_gen() which will do the
384160372Simp * transfers at a low level.
385160372Simp *
386160372Simp * Pointers passed in as part of iic_msg must be kernel pointers.
387160372Simp * Callers that have user addresses to manage must do so on their own.
388160372Simp */
389160372Simpint
390160372Simpiicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
391160372Simp{
392289097Sian
393160372Simp	return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs));
394160372Simp}
395160372Simp
396289726Sianint
397289726Sianiicbus_transfer_excl(device_t dev, struct iic_msg *msgs, uint32_t nmsgs,
398289726Sian    int how)
399289726Sian{
400289726Sian	device_t bus;
401289726Sian	int error;
402289726Sian
403289726Sian	bus = device_get_parent(dev);
404289726Sian	error = iicbus_request_bus(bus, dev, how);
405289726Sian	if (error == 0)
406289726Sian		error = IICBUS_TRANSFER(bus, msgs, nmsgs);
407289726Sian	iicbus_release_bus(bus, dev);
408289726Sian	return (error);
409289726Sian}
410289726Sian
411160372Simp/*
412160372Simp * Generic version of iicbus_transfer that calls the appropriate
413160372Simp * routines to accomplish this.  See note above about acceptable
414160372Simp * buffer addresses.
415160372Simp */
416160372Simpint
417167855Simpiicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
418160372Simp{
419214999Snwhitehorn	int i, error, lenread, lenwrote, nkid, rpstart, addr;
420167855Simp	device_t *children, bus;
421350031Savg	bool started;
422160372Simp
423182034Simp	if ((error = device_get_children(dev, &children, &nkid)) != 0)
424289097Sian		return (IIC_ERESOURCE);
425182034Simp	if (nkid != 1) {
426182034Simp		free(children, M_TEMP);
427289097Sian		return (IIC_ENOTSUPP);
428182034Simp	}
429167855Simp	bus = children[0];
430214999Snwhitehorn	rpstart = 0;
431167855Simp	free(children, M_TEMP);
432323419Sian	started = false;
433160372Simp	for (i = 0, error = 0; i < nmsgs && error == 0; i++) {
434214999Snwhitehorn		addr = msgs[i].slave;
435160372Simp		if (msgs[i].flags & IIC_M_RD)
436214999Snwhitehorn			addr |= LSB;
437160372Simp		else
438214999Snwhitehorn			addr &= ~LSB;
439214999Snwhitehorn
440214999Snwhitehorn		if (!(msgs[i].flags & IIC_M_NOSTART)) {
441214999Snwhitehorn			if (rpstart)
442214999Snwhitehorn				error = iicbus_repeated_start(bus, addr, 0);
443214999Snwhitehorn			else
444214999Snwhitehorn				error = iicbus_start(bus, addr, 0);
445323419Sian			if (error != 0)
446323419Sian				break;
447323419Sian			started = true;
448214999Snwhitehorn		}
449214999Snwhitehorn
450214999Snwhitehorn		if (msgs[i].flags & IIC_M_RD)
451214999Snwhitehorn			error = iicbus_read(bus, msgs[i].buf, msgs[i].len,
452214999Snwhitehorn			    &lenread, IIC_LAST_READ, 0);
453214999Snwhitehorn		else
454214999Snwhitehorn			error = iicbus_write(bus, msgs[i].buf, msgs[i].len,
455214999Snwhitehorn			    &lenwrote, 0);
456289084Sian		if (error != 0)
457289084Sian			break;
458214999Snwhitehorn
459350031Savg		if (!(msgs[i].flags & IIC_M_NOSTOP)) {
460214999Snwhitehorn			rpstart = 0;
461214999Snwhitehorn			iicbus_stop(bus);
462350031Savg		} else {
463350031Savg			rpstart = 1;	/* Next message gets repeated start */
464214999Snwhitehorn		}
465160372Simp	}
466323419Sian	if (error != 0 && started)
467289084Sian		iicbus_stop(bus);
468160372Simp	return (error);
469160372Simp}
470323446Sian
471323446Sianint
472323446Sianiicdev_readfrom(device_t slavedev, uint8_t regaddr, void *buffer,
473323446Sian    uint16_t buflen, int waithow)
474323446Sian{
475323446Sian	struct iic_msg msgs[2];
476323446Sian	uint8_t slaveaddr;
477323446Sian
478323446Sian	/*
479323446Sian	 * Two transfers back to back with a repeat-start between them; first we
480323446Sian	 * write the address-within-device, then we read from the device.
481323446Sian	 */
482323446Sian	slaveaddr = iicbus_get_addr(slavedev);
483323446Sian
484323446Sian	msgs[0].slave = slaveaddr;
485323446Sian	msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;
486323446Sian	msgs[0].len   = 1;
487323446Sian	msgs[0].buf   = &regaddr;
488323446Sian
489323446Sian	msgs[1].slave = slaveaddr;
490323446Sian	msgs[1].flags = IIC_M_RD;
491323446Sian	msgs[1].len   = buflen;
492323446Sian	msgs[1].buf   = buffer;
493323446Sian
494323446Sian	return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow));
495323446Sian}
496323446Sian
497323446Sianint iicdev_writeto(device_t slavedev, uint8_t regaddr, void *buffer,
498323446Sian    uint16_t buflen, int waithow)
499323446Sian{
500323446Sian	struct iic_msg msgs[2];
501323446Sian	uint8_t slaveaddr;
502323446Sian
503323446Sian	/*
504323446Sian	 * Two transfers back to back with no stop or start between them; first
505323446Sian	 * we write the address then we write the data to that address, all in a
506323446Sian	 * single transfer from two scattered buffers.
507323446Sian	 */
508323446Sian	slaveaddr = iicbus_get_addr(slavedev);
509323446Sian
510323446Sian	msgs[0].slave = slaveaddr;
511323446Sian	msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;
512323446Sian	msgs[0].len   = 1;
513323446Sian	msgs[0].buf   = &regaddr;
514323446Sian
515323446Sian	msgs[1].slave = slaveaddr;
516323446Sian	msgs[1].flags = IIC_M_WR | IIC_M_NOSTART;
517323446Sian	msgs[1].len   = buflen;
518323446Sian	msgs[1].buf   = buffer;
519323446Sian
520323446Sian	return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow));
521323446Sian}
522